- 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:10 UTC