Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
Traversable shadows are a requirement for a number of things like: - Generic page level libraries and polyfills that need to transform DOM nodes - Generic event handling libraries (ex. Pointer events) - Creating screenshots of the page by rendering every node to a canvas (ex. Google Feedback) - Creating awesome bookmarklets like Readability In our discussions with widget authors we'd either end up making shadows exposed by convention on almost all widget libraries under a common name as authors expect to be able to drop in libraries, polyfills and tools like Feedback, or we'd end up with awful hacks like overriding ShadowRoot or document.createElement. querySelector and friends will still stop at these boundaries, so you would never accidentally fall down into a ShadowRoot. That means that I doubt you'll get widgets being broken as Boris suggests because people aren't going to accidentally modify the inside of your widget. I'd also hate to prevent future innovation like Google Feedback which has turned out to be a critical component for Google product success. I can't share specific numbers, but it's had a very high impact and being able to be dropped into existing pages and just work was fundamental to that. While perhaps we can eventually solve that use case better, who knows what future ideas people will come up with. - E On Tue, Nov 6, 2012 at 3:44 PM, Dimitri Glazkov dglaz...@chromium.orgwrote: On Thu, Nov 1, 2012 at 9:02 AM, Boris Zbarsky bzbar...@mit.edu wrote: On 11/1/12 7:41 AM, Tab Atkins Jr. wrote: There was no good *reason* to be private by default Yes, there was. It makes it much simpler to author non-buggy components. Most component authors don't really contemplate how their code will behave if someone violates the invariants they're depending on in their shadow DOMs. We've run into this again and again with XBL. So pretty much any component that has a shadow DOM people can mess with but doesn't explicitly consider that it can happen is likely to be very broken. Depending on what exactly it does, the brokenness can be more or less benign, ranging from doesn't render right to leaks private user data to the world. As a general rule, we should favor being public over being private unless there's a good privacy or security reason to be private. As a general rule we should be making it as easy as possible to write non-buggy code, while still allowing flexibility. In my opinion. This has been my concern as well. The story that made me sway is the elementFromPoint story. It goes like this: we had an engineer come by and ask to add elementFromPoint to ShadowRoot API. ... this is a short story with a happy ending (https://www.w3.org/Bugs/Public/show_bug.cgi?id=18912), since ShadowRoot hasn't shipped anywhere yet. However, imagine all browsers ship Shadow DOM (oh glorious time), and there's a new cool DOM thing that we haven't thought of yet. Without ability to get into shadow trees and polyfill, we'll quickly see people throw nasty hacks at the problem, like they always do (see one that Dominic suggested here: https://www.w3.org/Bugs/Public/show_bug.cgi?id=15409#c5). And that seems like a bad smell. I am both excited and terrified. Excited, because discovering Angelina Farro's talk (http://www.youtube.com/watch?v=JNjnv-Gcpnw) makes me realize that this Web Components thing is starting to catch on. Terrified, because we gotta get this right. The Web is traditionally very monkey-patchey and pliable and our strides to make the boundaries hard will just breed perversion. Anyhow. Elliott has made several passionate arguments for travsersable shadow trees in person. Maybe he'll have a chance to chime in here. :DG
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Thu, Nov 1, 2012 at 6:43 AM, Maciej Stachowiak m...@apple.com wrote: On Nov 1, 2012, at 12:41 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: ... For example, being able to re-render the page manually via DOM inspection and custom canvas painting code. Google Feedback does this, for example. If shadows are only exposed when the component author thinks about it, and then only by convention, this means that most components will be un-renderable by tools like this. As Adam Barth often points out, in general it's not safe to paint pieces of a webpage into canvas without security/privacy risk. How does Google Feedback deal with non-same-origin images or videos or iframes, or with visited link coloring, to cite a few examples? Does it just not handle those things? We don't handle visited link coloring as there's no way to get that from JS. For images we proxy all images and do the actual drawing to the canvas in a nested iframe that's on the same domain as the proxy. For cross domain iframes we have a JS API that the frame can include that handles a special postMessage which serializes the entire page and then unserializes on the other side for rendering. Thankfully this case is extremely rare unlike web components where it turns out you end up with almost the entire page down in some component or another (ex. x-panel, x-conversation-view …). This of course requires you to have control of the cross origin page. For an architectural overview of Google Feedback's JS HTML rendering engine you can look at this presentation, slides 6 and 10 explain the image proxy: http://www.elliottsprehn.com/preso/fluentconf/ - E
Re: Re: Event.key complaints?
I wrote: Hence, what I think would be most usable in the real world would be making event.key a mapping back to un-shifted character values of a normal QUERTY (en-US) layout. Authors are asking for stable reference values for identifying keys, and that's the most stable and widely known reference keyboard layout. Gary responded: The main problem with using unmodified 'en-US' values is that it doesn't define values for keys that are not found on US keyboards. So, it's great for US keys, but completely ignores the rest of the world. Yep, and the solution to that is listing those keys and figuring out what their preferred key name should be. An implementation may still run into keys that have no identifier per the spec (so the spec says that implementations that are unable to identify a key must use the key value 'Unidentified') - but we should do a bit of work here to make sure as few keys as possible end up in this state. Thanks for coming up with your list :-) Consider the following problems with using 'en-US': * What should the 'key' value be for the B00 key (located next to the left shift - see the ISO/IEC9995-2 spec[1])? This is used in UK, Italian, Spanish, French, German and many other keyboards. Several layouts place here, some others , \ or -. AFAIK the most common seems to be , which also does not collide with any en-US unshifted key. * What should the 'key' value be for B11 key (next to the right shift)? This is used on Brazilian and Japanese keyboards. Seems Brazilian layouts have / and Japanese \ here, however these already exist on US layout. I guess event.key could be '/\' (only half-serious here). Any other proposals? * And C12 (tucked under Enter key when Enter takes 2 rows)? Keyboards with B00 usually have C12 as well. Go with UK and make event.key # ? * And E13 (between += and Backspace)? Found on Japanese (Yen key) and Russian keyboards. With apologies to Russia, we might make event.key be ¥ for this one. (Seems some Russian layouts have \ here - but then, the Russian layout documened by Microsoft on http://msdn.microsoft.com/en-us/goglobal/bb964651.aspx had no less than two other keys for \). * For B00, the USB code = 0x64, name = Non-US \ and |. * For B11, the USB code = 0x87, name = International1. * For C12, the USB code = 0x32, name = Non-US # and ~. * For E13, the USB code = 0x89, name = International3. I guess names like International1 could be used if we struggle.. As for the solution we need to come up with, it doesn't matter to me if it's: * encoded in the current 'key' field, or in a new field (although it'd be nice to have the 'key' field do the right thing). Sure, if we can agree on what that thing is :-) * a numeric value or a string (although I think a numeric value is preferable to avoid confusion with the 'char' value). Hm.. Personally I think a numeric value would be too easily confused with the keyCode value (which authors are used to), and in many cases it would actually be the very same value. If we want to make .key a number it's tempting to suggest throwing out .key and standardising .keyCode properly instead. (Some legacy issues will make this somewhat less reliable as an identify the key on the keyboard solution, e.g. A's keycode moving around on the keyboard when switching from QUERTY to AZERTY). * the exact USB codes or something similar that we derive from them. IMO it's nicer and more author-friendly to have some abstraction if we can make it easier to use.. But, we do need it to: * be able to uniquely identify each key on the keyboard. * be useful for all keys on all keyboards (and not just those that map nicely to 'en-US') * be straightforward to implement on all platforms. I don't think we can fulfil all three - particularly not the latter. That's just the way it is :-( -- Hallvord R. M. Steen Core tester, Opera Software
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On 11/8/12 1:45 AM, Elliott Sprehn wrote: That means that I doubt you'll get widgets being broken as Boris suggests because people aren't going to accidentally modify the inside of your widget. The problems start when people _maliciously_ modify the inside of your widget. Again, with XBL you don't get to accidentally modify the insides of anonymous content (shadow) trees. But there were all sorts of attack scenarious where people could modify them at all. I'd also hate to prevent future innovation like Google Feedback which has turned out to be a critical component for Google product success. I would like to understand more here. How does preventing touching the shadow tree by default prevent something like Google Feedback? -Boris
Re: Pre-fetch rough draft
On 06.11.2012, at 12:49, Julian Reschke wrote: On 2012-11-06 09:28, Sergey Nikitin wrote: On 05.11.2012, at 16:28, Julian Reschke wrote: Yes. Exactly. It's not about offline apps, it's about reducing loading time. There's already the prefetch link relation that you could use. You need at least two pages to start prefetching. Why two? And you can't prefetch anything for the first page. Yes, you can. Just use the first page's metadata instead of a separate prefetch manifest, I mean If you already downloaded a page you don't need any metadata. You can parse it and extract all urls from script/style tags (Ok. Except for a dynamically inserted ones). If you have single page application you can't prefetch. Why? And it's not always possible for browser to visit a page (cookie/password protected). It's always possible to visit the page; it just needs to return the relevant header fields. Maybe you never visited the page or your cookies are expired (or you logged out). And visiting any page (with all cookies/other headers) is irreversible action. It affects statistics, it could do something without your knowledge (marking message as read in your webmail?). Yes I know about special header browser should send to a server, but I've never heard about any site supporting it. Also generating a whole page just for metadata in it is a waste of server's CPU time. -- Sergey Nikitin
Re: Pre-fetch rough draft
On 04.11.2012, at 2:10, Yehuda Katz wrote: Does this overlap with SPDY preloaded? I can't find anything about SPDY preloaded. Is it server push and server hint http://www.chromium.org/spdy/link-headers-and-server-hint ? -- Sergey Nikitin
Re: Pre-fetch rough draft
On 2012-11-08 17:31, Sergey Nikitin wrote: ... Maybe you never visited the page or your cookies are expired (or you logged out). And visiting any page (with all cookies/other headers) is irreversible action. It affects statistics, it could do something without your knowledge (marking message as read in your webmail?). Yes I know about special header browser should send to a server, but I've never heard about any site supporting it. ... Visiting a page should be a safe action; we shouldn't design extensions to address cases where people get this wrong. Also generating a whole page just for metadata in it is a waste of server's CPU time. You don't need to generate the page (there's the HTTP HEAD method). Best regards, Julian
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Thu, Nov 8, 2012 at 8:13 AM, Boris Zbarsky bzbar...@mit.edu wrote: On 11/8/12 1:45 AM, Elliott Sprehn wrote: That means that I doubt you'll get widgets being broken as Boris suggests because people aren't going to accidentally modify the inside of your widget. The problems start when people _maliciously_ modify the inside of your widget. Again, with XBL you don't get to accidentally modify the insides of anonymous content (shadow) trees. But there were all sorts of attack scenarious where people could modify them at all. If you're worried about malicious attacks on your widget, shadows being private is not enough. You need a whole new scripting context. I can override all the String and Array methods, DOM prototype methods, document.createElement, document.implementation methods, MutationObserver etc. or even the ShadowRoot constructor with the current API and still likely capture the inside of your component. This is JavaScript after all. :) You're much better off using a public shadow and then putting your whole widget in a cross domain iframe to get a new scripting context instead of depending on the false security of a private shadow. I'd also hate to prevent future innovation like Google Feedback which has turned out to be a critical component for Google product success. I would like to understand more here. How does preventing touching the shadow tree by default prevent something like Google Feedback? Google Feedback is an HTML rendering engine written in JS. To render the document you need access to every DOM node so you can draw it to a canvas. In the world of web components much, or often all, of your web application ends up inside of a component. We can imagine Gmail is something like: x-toolbar/x-toolbar x-panel x-label-sidebar/x-label-sidebar x-conversation/x-conversation /x-panel Google Feedback would be unnable to access the private shadow tree where the actual content of the page is so your screenshot would be blank. Today Google Feedback just works on most pages on the web and can be activated through a bookmarklet on any website, even ones that Google does not control. In the future this wouldn't be possible if shadows were private by default and authors didn't consider all future library and widget integrations. For more information about Google Feedback see my recent architecture presentation: http://elliottsprehn.com/preso/fluentconf/ Another example is Readability: http://www.readability.com/bookmarklets Once the articles on news websites are actually just x-news-article articleId={bindingForArticleId}/x-news-article and load from the model into their shadow they become hidden from bookmarklets that wish to traverse down into them making future innovations like Readbility difficult without super hacks. - E
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots.
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Nov 6, 2012, at 3:29 PM, Dimitri Glazkov dglaz...@google.com wrote: On Thu, Nov 1, 2012 at 8:39 AM, Tab Atkins Jr. jackalm...@gmail.com wrote: 6) The isolated setting essentially means that there's a new document and scripting context for this shadow subtree (specifics TBD). Watch https://www.w3.org/Bugs/Public/show_bug.cgi?id=16509 for progress. That seems like a whole separate feature - perhaps we should figure out private vs public first. It would be good to know the use cases for this feature over using private or something like seamless iframes. Yeah, sure. It's useful to bring up at the same time, though, because there are some decent use-cases that sound at first blush like they should be private, but really want even stronger security/isolation constraints. An existing example, iirc, is the Google +1 button widget. Every single +1 includes an iframe so it can do some secure scripting without the page being able to reach in and fiddle with things. What are the advantages to using an isolated component for the +1 button instead if an iframe, or a private component containing an iframe? I'm not 100% sure (Dimitri can answer better), but I think it's because we can do a somewhat more lightweight isolation than what a full iframe provides. IIRC, several of our use-cases *really* want all of the instances of a given component to use the same scripting context, because there's going to be a lot of them, and they all need the same simple data; they'd gain no benefit from being fully separate and paying the cost of a thousand unique scripting contexts. Is that the semantics isolated would have? All instances of the same component are in the same scripting context, but one separate from the page? I assumed that new document and scripting context for this shadow subtree would mean there's a new one per instance, and the document plus the scripting context is most of the cost of an iframe. Yup. The typical example that the Google+ people point out to me is techcrunch.com. The count of iframes had gotten so high that it affected performance to the point where the crunchmasters had to fake the buttons (and reveal them on hover, which is tangential to the story and may or may not have been the wisest choice). With isolated shadow trees, the number of scripting contexts would equal then number of button-makers, and offer additional opportunities like sharing styles among instances. OK, it wasn't clear that the separate document and scripting context for isolated components would be per unique component, rather than per-instance. That does seem like a meaningfully different behavior. One thing that makes me nervous about theisolated idea, is thata scripting context is normally bound one-to-one to either a browsing context or a worker; and having multiple scripting contexts per browsing context seems like it could be tricky to implement and may have security risks. But I don't have any more concrete objection at this time. I think that Workers or something very much like them is a productive direction to look in for the isolated components, actually. Wouldn't that require making the DOM and UI event dispatch threadsafe (which are likely not very practical things to do)? Flipping it around, isolation also serves as a great way for the *page* to protect itself from the *component*. There are tons of components that have absolutely no need to interact with the outside page, so sealing them off loses you nothing and gains you peace of mind when worrying about whether you should include some random plugins you found on your favorite component library site. Would the page be able to choose to make a component isolated without the cooperation of the component? Or alternately load components in such a way that only isolated ones would succeed? I think we'd like that, but haven't thought it through very hard yet. Isolation as a problem is something that's often considered in design discussions (hence it being brought up here), but it's in a distant future in relation to actual progress of the spec. If there were Shadow DOM L2, that would a nice place to start. Maybe it should be set aside from this public vs private discussion for now then. If it may be desirable to force isolated from the outside, then that makes it substantially different from the public vs private distinction, which should be completely under the control of the component. There's not much point to discussing isolated without having a handle on this aspect of its design. Regards, Maciej
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
Sure. Here's a simple example without getting into traversable shadow trees (those are still being discussed in a different thread): A1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = new ShadowRoot(element); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); A2) Using addShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = element.addShadowRoot(); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); Now with traversable shadow trees: B1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = new ShadowRoot(element); alert(root === element.shadowRoot); // true var root2 = new ShadowRoot(element); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true B2) Using addShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot(); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true :DG On Thu, Nov 8, 2012 at 9:42 AM, Maciej Stachowiak m...@apple.com wrote: Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots.
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Thu, Nov 8, 2012 at 9:48 AM, Maciej Stachowiak m...@apple.com wrote: On Nov 6, 2012, at 3:29 PM, Dimitri Glazkov dglaz...@google.com wrote: On Thu, Nov 1, 2012 at 8:39 AM, Tab Atkins Jr. jackalm...@gmail.com wrote: 6) The isolated setting essentially means that there's a new document and scripting context for this shadow subtree (specifics TBD). Watch https://www.w3.org/Bugs/Public/show_bug.cgi?id=16509 for progress. That seems like a whole separate feature - perhaps we should figure out private vs public first. It would be good to know the use cases for this feature over using private or something like seamless iframes. Yeah, sure. It's useful to bring up at the same time, though, because there are some decent use-cases that sound at first blush like they should be private, but really want even stronger security/isolation constraints. An existing example, iirc, is the Google +1 button widget. Every single +1 includes an iframe so it can do some secure scripting without the page being able to reach in and fiddle with things. What are the advantages to using an isolated component for the +1 button instead if an iframe, or a private component containing an iframe? I'm not 100% sure (Dimitri can answer better), but I think it's because we can do a somewhat more lightweight isolation than what a full iframe provides. IIRC, several of our use-cases *really* want all of the instances of a given component to use the same scripting context, because there's going to be a lot of them, and they all need the same simple data; they'd gain no benefit from being fully separate and paying the cost of a thousand unique scripting contexts. Is that the semantics isolated would have? All instances of the same component are in the same scripting context, but one separate from the page? I assumed that new document and scripting context for this shadow subtree would mean there's a new one per instance, and the document plus the scripting context is most of the cost of an iframe. Yup. The typical example that the Google+ people point out to me is techcrunch.com. The count of iframes had gotten so high that it affected performance to the point where the crunchmasters had to fake the buttons (and reveal them on hover, which is tangential to the story and may or may not have been the wisest choice). With isolated shadow trees, the number of scripting contexts would equal then number of button-makers, and offer additional opportunities like sharing styles among instances. OK, it wasn't clear that the separate document and scripting context for isolated components would be per unique component, rather than per-instance. That does seem like a meaningfully different behavior. One thing that makes me nervous about theisolated idea, is thata scripting context is normally bound one-to-one to either a browsing context or a worker; and having multiple scripting contexts per browsing context seems like it could be tricky to implement and may have security risks. But I don't have any more concrete objection at this time. I think that Workers or something very much like them is a productive direction to look in for the isolated components, actually. Wouldn't that require making the DOM and UI event dispatch threadsafe (which are likely not very practical things to do)? Flipping it around, isolation also serves as a great way for the *page* to protect itself from the *component*. There are tons of components that have absolutely no need to interact with the outside page, so sealing them off loses you nothing and gains you peace of mind when worrying about whether you should include some random plugins you found on your favorite component library site. Would the page be able to choose to make a component isolated without the cooperation of the component? Or alternately load components in such a way that only isolated ones would succeed? I think we'd like that, but haven't thought it through very hard yet. Isolation as a problem is something that's often considered in design discussions (hence it being brought up here), but it's in a distant future in relation to actual progress of the spec. If there were Shadow DOM L2, that would a nice place to start. Maybe it should be set aside from this public vs private discussion for now then. Sure thing. I realize now it was a distraction in this discussion. If it may be desirable to force isolated from the outside, then that makes it substantially different from the public vs private distinction, which should be completely under the control of the component. There's not much point to discussing isolated without having a handle on this aspect of its design. Regards, Maciej
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Nov 8, 2012, at 2:15 AM, Elliott Sprehn espr...@gmail.com wrote: On Thu, Nov 1, 2012 at 6:43 AM, Maciej Stachowiak m...@apple.com wrote: On Nov 1, 2012, at 12:41 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: ... For example, being able to re-render the page manually via DOM inspection and custom canvas painting code. Google Feedback does this, for example. If shadows are only exposed when the component author thinks about it, and then only by convention, this means that most components will be un-renderable by tools like this. As Adam Barth often points out, in general it's not safe to paint pieces of a webpage into canvas without security/privacy risk. How does Google Feedback deal with non-same-origin images or videos or iframes, or with visited link coloring, to cite a few examples? Does it just not handle those things? We don't handle visited link coloring as there's no way to get that from JS. For images we proxy all images and do the actual drawing to the canvas in a nested iframe that's on the same domain as the proxy. For cross domain iframes we have a JS API that the frame can include that handles a special postMessage which serializes the entire page and then unserializes on the other side for rendering. Thankfully this case is extremely rare unlike web components where it turns out you end up with almost the entire page down in some component or another (ex. x-panel, x-conversation-view …). This of course requires you to have control of the cross origin page. For an architectural overview of Google Feedback's JS HTML rendering engine you can look at this presentation, slides 6 and 10 explain the image proxy: http://www.elliottsprehn.com/preso/fluentconf/ Are these types of workarounds adequate for the web components case? If not, why not? Regards, Maciej
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
That _is_ pretty nice, but we can add this as a second argument to the constructor, as well: root = new ShadowRoot(element, { applyAuthorSheets: false, resetStyleInheritance: true }); At this point, the stakes are primarily in aesthetics... Which makes the whole question so much more difficult to address objectively. :DG On Thu, Nov 8, 2012 at 9:54 AM, Elliott Sprehn espr...@google.com wrote: The real sugar I think is in the dictionary version of addShadowRoot: root = element.addShadowRoot({ applyAuthorSheets: false, resetStyleInheritance: true }) On Thu, Nov 8, 2012 at 9:49 AM, Dimitri Glazkov dglaz...@google.com wrote: Sure. Here's a simple example without getting into traversable shadow trees (those are still being discussed in a different thread): A1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = new ShadowRoot(element); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); A2) Using addShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = element.addShadowRoot(); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); Now with traversable shadow trees: B1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = new ShadowRoot(element); alert(root === element.shadowRoot); // true var root2 = new ShadowRoot(element); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true B2) Using addShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot(); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true :DG On Thu, Nov 8, 2012 at 9:42 AM, Maciej Stachowiak m...@apple.com wrote: Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots.
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On Thu, Nov 8, 2012 at 9:55 AM, Maciej Stachowiak m...@apple.com wrote: On Nov 8, 2012, at 2:15 AM, Elliott Sprehn espr...@gmail.com wrote: On Thu, Nov 1, 2012 at 6:43 AM, Maciej Stachowiak m...@apple.com wrote: On Nov 1, 2012, at 12:41 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: For example, being able to re-render the page manually via DOM inspection and custom canvas painting code. Google Feedback does this, for example. If shadows are only exposed when the component author thinks about it, and then only by convention, this means that most components will be un-renderable by tools like this. As Adam Barth often points out, in general it's not safe to paint pieces of a webpage into canvas without security/privacy risk. How does Google Feedback deal with non-same-origin images or videos or iframes, or with visited link coloring, to cite a few examples? Does it just not handle those things? We don't handle visited link coloring as there's no way to get that from JS. For images we proxy all images and do the actual drawing to the canvas in a nested iframe that's on the same domain as the proxy. For cross domain iframes we have a JS API that the frame can include that handles a special postMessage which serializes the entire page and then unserializes on the other side for rendering. Thankfully this case is extremely rare unlike web components where it turns out you end up with almost the entire page down in some component or another (ex. x-panel, x-conversation-view …). This of course requires you to have control of the cross origin page. For an architectural overview of Google Feedback's JS HTML rendering engine you can look at this presentation, slides 6 and 10 explain the image proxy: http://www.elliottsprehn.com/preso/fluentconf/ Are these types of workarounds adequate for the web components case? If not, why not? No, it should be very obvious that you can't do similar workarounds. The inability to detect history state is largely unimportant. It's a trivial loss for most use-cases in this area. The workaround for the crossorigin security issue (by proxying images) is completely inapplicable for Components. With an image, you have all the information you need right there at the DOM level - you grab the URL, run a server-side proxy, and you're done. That's the entire content of the image. There is obviously nothing similar for components with hidden shadows. ~TJ
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
The real sugar I think is in the dictionary version of addShadowRoot: root = element.addShadowRoot({ applyAuthorSheets: false, resetStyleInheritance: true }) On Thu, Nov 8, 2012 at 9:49 AM, Dimitri Glazkov dglaz...@google.com wrote: Sure. Here's a simple example without getting into traversable shadow trees (those are still being discussed in a different thread): A1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = new ShadowRoot(element); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); A2) Using addShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = element.addShadowRoot(); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); Now with traversable shadow trees: B1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = new ShadowRoot(element); alert(root === element.shadowRoot); // true var root2 = new ShadowRoot(element); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true B2) Using addShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot(); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true :DG On Thu, Nov 8, 2012 at 9:42 AM, Maciej Stachowiak m...@apple.com wrote: Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots.
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
True, though that's actually one character longer, probably two with normal formatting ;P new ShadowRoot(element,{ element.addShadowRoot({ I'm more concerned about the constructor with irreversible side effects of course. - E On Thu, Nov 8, 2012 at 9:57 AM, Dimitri Glazkov dglaz...@google.com wrote: That _is_ pretty nice, but we can add this as a second argument to the constructor, as well: root = new ShadowRoot(element, { applyAuthorSheets: false, resetStyleInheritance: true }); At this point, the stakes are primarily in aesthetics... Which makes the whole question so much more difficult to address objectively. :DG On Thu, Nov 8, 2012 at 9:54 AM, Elliott Sprehn espr...@google.com wrote: The real sugar I think is in the dictionary version of addShadowRoot: root = element.addShadowRoot({ applyAuthorSheets: false, resetStyleInheritance: true }) On Thu, Nov 8, 2012 at 9:49 AM, Dimitri Glazkov dglaz...@google.com wrote: Sure. Here's a simple example without getting into traversable shadow trees (those are still being discussed in a different thread): A1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = new ShadowRoot(element); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); A2) Using addShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = element.addShadowRoot(); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); Now with traversable shadow trees: B1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = new ShadowRoot(element); alert(root === element.shadowRoot); // true var root2 = new ShadowRoot(element); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true B2) Using addShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot(); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true :DG On Thu, Nov 8, 2012 at 9:42 AM, Maciej Stachowiak m...@apple.com wrote: Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots.
Re: [webcomponents]: Changing API from constructable ShadowRoot to factory-like
addShadowRoot seem wrong to me to. Usually add* methods takes an argument of something that is supposed to be added to the context object. If we are going with a factory function I think that createShadowRoot is the right name even though create methods have a lot of bad history in the DOM APIs. On Thu, Nov 8, 2012 at 1:01 PM, Elliott Sprehn espr...@google.com wrote: True, though that's actually one character longer, probably two with normal formatting ;P new ShadowRoot(element,{ element.addShadowRoot({ I'm more concerned about the constructor with irreversible side effects of course. - E On Thu, Nov 8, 2012 at 9:57 AM, Dimitri Glazkov dglaz...@google.com wrote: That _is_ pretty nice, but we can add this as a second argument to the constructor, as well: root = new ShadowRoot(element, { applyAuthorSheets: false, resetStyleInheritance: true }); At this point, the stakes are primarily in aesthetics... Which makes the whole question so much more difficult to address objectively. :DG On Thu, Nov 8, 2012 at 9:54 AM, Elliott Sprehn espr...@google.com wrote: The real sugar I think is in the dictionary version of addShadowRoot: root = element.addShadowRoot({ applyAuthorSheets: false, resetStyleInheritance: true }) On Thu, Nov 8, 2012 at 9:49 AM, Dimitri Glazkov dglaz...@google.com wrote: Sure. Here's a simple example without getting into traversable shadow trees (those are still being discussed in a different thread): A1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = new ShadowRoot(element); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); A2) Using addShadowRoot: var element = document.querySelector('div#foo'); // let's add a shadow root to element var shadowRoot = element.addShadowRoot(); // do work with it.. shadowRoot.applyAuthorSheets = false; shadowRoot.appendChild(myDocumentFragment); Now with traversable shadow trees: B1) Using constructable ShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = new ShadowRoot(element); alert(root === element.shadowRoot); // true var root2 = new ShadowRoot(element); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true B2) Using addShadowRoot: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot(); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true :DG On Thu, Nov 8, 2012 at 9:42 AM, Maciej Stachowiak m...@apple.com wrote: Could you please provide equivalent code examples using both versions? Cheers, Maciej On Nov 7, 2012, at 10:36 AM, Dimitri Glazkov dglaz...@google.com wrote: Folks, Throughout the year-long (whoa!) history of the Shadow DOM spec, various people commented on how odd the constructable ShadowRoot pattern was: var root = new ShadowRoot(host); // both creates an instance *and* makes an association between this instance and host. People (I cc'd most of them) noted various quirks, from the side-effectey constructor to relatively uncommon style of the API. I once was of the strong opinion that having a nice, constructable object has better ergonomics and would overcome the mentioned code smells. But... As we're discussing traversable shadows and the possibility of having Element.shadowRoot, the idea of changing to a factory pattern now looks more appealing: var element = document.querySelector('div#foo'); alert(element.shadowRoot); // null var root = element.addShadowRoot({ resetStyleInheritance: true }); alert(root === element.shadowRoot); // true var root2 = element.addShadowRoot(); alert(root === element.shadowRoot); // false alert(root2 === element.shadowRoot); // true You gotta admit this looks very consistent and natural relative to how DOM APIs work today. We could still keep constructable object syntax as alternative method or ditch it altogether and make calling constructor throw an exception. What do you think, folks? In the spirit of last night's events, let's vote: 1) element.addShadowRoot rocks! Let's make it the One True Way! 2) Keep ShadowRoot constructable! Factories stink! 3) Let's have both! 4) element.addShadowRoot, but ONLY if we have traversable shadow trees 5) Kodos. :DG P.S. I would like to retain the atomic quality of the operation: instantiate+associate in one go. There's a whole forest of problems awaits those who contemplate detached shadow roots. -- erik
Re: [webcomponents]: Making Shadow DOM Subtrees Traversable
On 11/8/12 9:28 AM, Elliott Sprehn wrote: If you're worried about malicious attacks on your widget, shadows being private is not enough. You need a whole new scripting context. Er... yes, you do. Do widgets not get that? If not, that's pretty broken... Google Feedback is an HTML rendering engine written in JS. To render the document you need access to every DOM node so you can draw it to a canvas. I see. It'll still break with things like images and whatnot if you want to extract the data from that canvas (in general, modulo CORS etc), but yes, I can see how not being able to get inside components is a problem. I wonder whether making access to the insides of components work based on same-origin restrictions + CORS makes sense. -Boris