> On Feb 16, 2014, at 1:21 AM, Alex Russell <slightly...@google.com> wrote:
> 
>> On Sun, Feb 16, 2014 at 12:52 AM, Ryosuke Niwa <rn...@apple.com> wrote:
>>> On Feb 16, 2014, at 12:42 AM, Ryosuke Niwa <rn...@apple.com> wrote:
>>> 
>>>> On Feb 15, 2014, at 11:30 PM, Alex Russell <slightly...@google.com> wrote:
>>>> 
>>>>> On Sat, Feb 15, 2014 at 4:57 PM, Ryosuke Niwa <rn...@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:
>>>>> If the content element's shadow host's node tree doesn't contain 
>>>>> _element_, throw HierarchyRequestError.
>>>>> If element is already in some other content element's _explicitly 
>>>>> inserted nodes_
>>>>> then call remove with _element_ on that content element.
>>>>> Append _element_ to the end of _explicitly inserted nodes_.
>>>>> 
>>>>> remove(Element element) must act according to the following algorithm:
>>>>> 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.
>>>>> 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:
>>>>> It doesn't require UA calling back to JS constantly to match elements
>>>>> 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.

And what exactly is the point of having this callback?  Are UAs supposed to 
call it automatically in some situations?  If so, when?

- R. Niwa

Reply via email to