- From: Alex Russell <slightlyoff@google.com>
- Date: Sun, 16 Feb 2014 01:21:13 -0800
- To: Ryosuke Niwa <rniwa@apple.com>
- Cc: Hayato Ito <hayato@google.com>, Dimitri Glazkov <dglazkov@chromium.org>, William Chen <wchen@mozilla.com>, Jonas Sicking <jonas@sicking.cc>, public-webapps <public-webapps@w3.org>, "www-tag@w3.org List" <www-tag@w3.org>, Yehuda Katz <wycats@gmail.com>, Dave Herman <dherman@mozilla.com>
- Message-ID: <CANr5HFXVEQYbKHjHuVXW3xbh4YbuBNuJLJnjb-P0Nj9yRK4zHw@mail.gmail.com>
On Sun, Feb 16, 2014 at 12:52 AM, Ryosuke Niwa <rniwa@apple.com> wrote: > On Feb 16, 2014, at 12:42 AM, Ryosuke Niwa <rniwa@apple.com> wrote: > > On Feb 15, 2014, at 11:30 PM, Alex Russell <slightlyoff@google.com> wrote: > > On Sat, Feb 15, 2014 at 4:57 PM, Ryosuke Niwa <rniwa@apple.com> wrote: > >> Hi all, >> >> I’d like to propose one solution for >> >> [Shadow]: Specify imperative API for node distribution >> https://www.w3.org/Bugs/Public/show_bug.cgi?id=18429 >> >> because select content attribute doesn’t satisfy the needs of >> framework/library authors to support conditionals in their templates, >> and doesn’t satisfy my random image element use case below. >> >> >> *== Use Case ==* >> Random image element is a custom element that shows one of child img >> elements chosen uniformally random. >> >> e.g. the markup of a document that uses random-image-element may look >> like this: >> <random-image-element> >> <img src="kitten.jpg"> >> <img src="cat.jpg"> >> <img src="webkitten.jpg"> >> </random-image-element> >> >> random-image-element displays one out of the three img child elements >> when a user clicks on it. >> >> As an author of this element, I could modify the DOM and add style >> content attribute directly on those elements >> but I would rather use shadow DOM to encapsulate the implementation. >> >> >> *== API Proposal ==* >> >> Add two methods void add(Element) and void remove(Element) to content >> element. >> (We can give them more descriptive names. I matched select element for >> now). >> >> Each content element has an ordered list of **explicitly inserted nodes* >> *. >> >> add(Element element) must act according to the following algorithm: >> >> 1. If the content element's shadow host's node tree doesn't contain _ >> *element*_, throw HierarchyRequestError. >> 2. If element is already in some other content element's _*explicitly >> inserted nodes*_ >> then call remove with _*element*_ on that content element. >> 3. Append _*element*_ to the end of _*explicitly inserted nodes*_. >> >> >> remove(Element element) must act according to the following algorithm: >> >> 1. If the content element's _*explicitly inserted nodes*_ does not >> contain _*element*_, throw NotFoundError. >> >> > Throwing exceptions is hostile to usability. > > > If people are so inclined, we don’t have to throw an exception and > silently fail. > > >> 1. Remove _*element*_ from _*explicitly inserted nodes*_. >> >> >> The idea here is that _*explicitly inserted nodes*_ of an insertion >> point A would be the list of distributed nodes of A but >> I haven't figured out exactly how _*explicitly inserted nodes*_ should >> interact with select content attribute. >> >> I think the simplest model would be _*explicitly inserted nodes*_ simply >> overriding whatever select content attribute was >> trying to do but I don't have a strong opinion about how they should >> interact yet. >> >> I don't think it makes sense to support redistributions, etc... at least >> in the initial API. >> >> >> This proposal has an advantage over the existing proposal on >> https://www.w3.org/Bugs/Public/show_bug.cgi?id=18429: >> >> 1. It doesn't require UA calling back to JS constantly to match >> elements >> 2. Point 1 implies we don't expose when distribution happens for >> select content attribute. >> >> This doesn't seem like progress. I'd hope an imperative API would, > instead, be used to explain how the existing system works and then propose > layering that both accommodates the existing system and opens new areas for > programmatic use. > > We can imagine such a system for programmatic Shadow DOM with some sort of > distribute(Element) callback that can be over-ridden and use add/remove > methods to do final distribution. > > > The problem here is that such a callback must be called on every node upon > any state change because UAs have no way of knowing what causes > redistribution for a given component. As as a matter of fact, some use > cases may involve changing the node distributions based on some JS objects > state. And having authors codify such conditions for UAs is much more > cumbersome than letting them re-distribute nodes at their will. > > > To give you more concrete example, in the case of my random image element, > how can UA notice that user clicking on the element should trigger > reconstruction of the composed tree? > Isn't the stated design of the custom element that it re-constructs the composed tree with a random image every time it's clicked? It's not actually clear what you wanted here because there isn't any example code to go on. > Should the script call some method like redistribute() on the host upon > click? But then, since the element needs to pick a child uniformly random, > it probably needs to keep track of the number of children to be distributed > and return true exactly when that node was passed into the callback. > That’s an extremely cumbersome API at least for my use case. > I have the sense that if you produced example code you'd be able to make a better guess about what's onerous and what isn't. As it is, we're debating hypotheticals. Here's a version of your component based on my proposal. I don't feel it's particularly cumbersome in context: var log = console.log.bind(console); var randomInt = function(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } var rip = Object.create(HTMLElement.prototype); rip.distributeCallback = function(children) { while(this.shadowRoot.children.length) { this.shadowRoot.remove(this.shadowRoot.children[0]); } var i = randomInt(0, children.length-1); this.shadowRoot.add(children[i]); }; var RandomImage = document.registerElement( "random-image", { prototype: rip }); Obviously, the element needs to add a click handler to call distributeCallback() manually with this.children, but I don't see how that's hard. What did I miss?
Received on Sunday, 16 February 2014 09:22:11 UTC