This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 22344 - [Shadow]: Distribute into <shadow>, project into older shadow root
Summary: [Shadow]: Distribute into <shadow>, project into older shadow root
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC Windows NT
: P2 normal
Target Milestone: ---
Assignee: Hayato Ito
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
: 19404 (view as bug list)
Depends on:
Blocks: 22715
  Show dependency treegraph
 
Reported: 2013-06-12 19:54 UTC by Scott Miles
Modified: 2014-03-25 16:36 UTC (History)
10 users (show)

See Also:


Attachments

Description Scott Miles 2013-06-12 19:54:07 UTC
Nesting shadows allows for a natural form of inheritance, but as such it's missing the critical ability to manage content through the inheritance chain.

Users are trying to do things like this:

  <!-- use inherited shadow, but supply static content -->
  <shadow>[static content><shadow>

  <!-- use inherited shadow, add some decoration to user content -->
  <shadow><icon></icon><content></content><shadow>

The notion is that the children of the <shadow> become the POOL for distribution into the inherited shadow root, instead of using the left overs.

Currently the content of <shadow> is defined as fallback content, which to my knowledge is 100% unused so far in practice.
Comment 1 Scott Miles 2013-06-12 19:57:26 UTC
To be clear, I mean to suggest that the POOL for <shadow> in this case

  <!-- use inherited shadow, add some decoration to user content -->
  <shadow><icon></icon><content></content><shadow>

is 

  <icon> + the nodes distributed to <content>

IOW, this is a reprojection concept.
Comment 2 Dominic Cooney 2013-06-13 09:04:06 UTC
This is a *superb* idea.

I tried prototyping this in Blink today, and it will involve some work to implement. However the power and simplicity of this idea is evident.

For fans of the existing behavior, the existing behavior is easy to produce with:

<shadow><content></content></shadow>

(If there was a way to control the order of distribution the existing behavior can be implemented with complete generality, but that is a separate bug.)

What is proposed here is much more powerful and ends the reliance on treating the shadow you're stacked on top of as a completely black box--just decorate the edges--or a completely clear box--have to have full knowledge of the insertion points below you in the stack to do anything useful.

FWIW I think that this is a deeper change than just tweaking POOL. For example you want events to be retargeted, etc. through the points of reprojection.

I support this change; I think it is a wonderful idea; I think it will make using Shadow DOM with Custom Elements and subtyping feasible.
Comment 3 Jan Miksovsky 2013-06-13 22:33:05 UTC
I'm also of the opinion that this would be a huge win. I've built a number of component-oriented web apps using a framework that effectively supports the feature proposed here. In the process of porting components from that framework to custom elements with shadow DOM, I've been running into some significant challenges. See http://blog.quickui.org/2013/06/11/puzzle-define-html-custom-element-subclasses-that-can-fill-in-base-class-insertion-points/ for a discussion of those issues; also see data in the first comment of that post which suggest this feature would receive significant use in custom element collections.

I believe this proposal is a natural extension to the Shadow DOM conceptual model. I, and at least one other early Polymer user, independently expected <shadow> to work this way — and were disappointed when it did not. This is a statistically insignificant set of data points, but nevertheless, the fact that early Shadow DOM users anticipate that this will work suggests it would be a very natural extension of the spec'ed behavior.

One note: I would propose that, if <shadow>stuff</shadow> appears in a shadow subtree with no older subtree (that is, there is no older shadow to fill in), then "stuff" should get rendered as default content. This is the current behavior in which <shadow> renders default content when no older subtree exists.
Comment 4 Dominic Cooney 2013-06-13 23:54:36 UTC
I would love to hear from someone with XBL experience what they think of this.

I think this feature will put more pressure on running content distribution in something more flexible than document order.

In thinking more about the effect on the spec, this means the definition of active and inert insertion points needs to be tweaked; content elements with exactly one shadow element ancestor and no intervening content element ancestors is active now.

In Blink we apparently allow the dubious feature of adding a ShadowRoot to an insertion point, and render it if the insertion point is inert. I'm not sure if that is enshrined in the spec but I would be keen to restrict that to simplifying the implementation now that <shadow> can both be parent of distributed nodes and get nodes distributed to it.

Do you think that we can now make all content elements without content element ancestors active? For example, could you nest a content element in a *second* shadow element for the purpose of "deleting" those nodes?

(In reply to comment #3)
> One note: I would propose that, if <shadow>stuff</shadow> appears in a
> shadow subtree with no older subtree (that is, there is no older shadow to
> fill in), then "stuff" should get rendered as default content. This is the
> current behavior in which <shadow> renders default content when no older
> subtree exists.

Yes. I think the spec should address this by specifying that all elements have a ShadowRoot. (It is probably <content></content>, but now that <shadow> is sane, that detail is irrelevant.)
Comment 5 Boris Zbarsky 2013-06-14 03:32:27 UTC
I feel like I'm missing a tremendous amount of context here.  What exactly is the problem we're trying to solve, and what is the proposed solution?

It sounds like the idea is to be able to have component A inherit from component B, for component B to define some sort of shadow tree and for component A to also define a shadow tree that doesn't just override the one from B but instead interacts with it somehow, right?
Comment 6 Dominic Cooney 2013-06-14 06:45:47 UTC
(In reply to comment #5)
> I feel like I'm missing a tremendous amount of context here.  What exactly
> is the problem we're trying to solve, and what is the proposed solution?

First, a specific problem:

> It sounds like the idea is to be able to have component A inherit from
> component B, for component B to define some sort of shadow tree and for
> component A to also define a shadow tree that doesn't just override the one
> from B but instead interacts with it somehow, right?

Basically, yes. Here's an example:

We have a component x-icon-button. Its "markup API" is DOM like this:

<x-icon-button>
  <img class="icon" ...>
  (button text)
</x-icon-button>

It sets up Shadow DOM, you don't know the details, it is part of the x-icon-button abstraction.

Now I want to define x-warning-button. Warning buttons are also x-icon-buttons (maybe there is API for shrinking to a small version that just displays the icon or something.)

I want to have markup like this:

<x-warning-button>
  Launch missiles
</x-warning-button>

My intent is that all warning buttons have the same warning icon. How do I do it?

There are a few approaches you can take today, but all of them have problems, for example:

1. Use composition: Put another x-icon-button inside the x-warning-button's Shadow DOM. Don't use <shadow>. The major downside is that you have to forward all of the API into the x-icon-button, and there are some things that are basically impossible to forward, like styles.

2. Use cut-and-paste: Open up the x-icon-button and duplicate it into x-warning-button. There might be a few bits of pure behavior you can share in a behavior-only base type. The major downside is code duplication and less reuse.

You have an equivalent problem most times you have more than one ShadowRoot attached to an element.

Let me use an analogy to explain this problem in general:

Today, the child nodes of a shadow host are like a set of global variables. (The variable "names" are a selector which matches them.) Once you've used a variable  the variable is "used up" (because a node can only be rendered once.)

The <shadow> element is like GOSUB. It "invokes" the next ShadowRoot whose <content> elements might read from the set of variables.

What we're proposing is to make <shadow> like a function call; the next ShadowRoot gets its own "parameter list" from the body of the <shadow>. It doesn't chew on global variables any more.

Here's an example:

<button id="host">
  Launch missiles
</button>

#host's youngest ShadowRoot
{SR}
  <shadow>
    <img src="..." alt="Warning!" class="icon">
    <content></content>
  </shadow>
{/SR}

#host's older ShadowRoot
{SR}
  <div class="icon-container">
    <content select="img.icon"></content>
  </div>
  <content></content>
{/SR}

The youngest ShadowRoot is processed first and produces this intermediate tree:

<shadow>
  <img src="..." alt="Warning!" class="icon">
  Launch missiles
</shadow>

Then the <shadow> is processed, but instead of drawing from the host's child list, it draws from the <shadow>'s distributed child list. So the final flattened tree would be:

<button id="host">
  <div class="icon-container">
    <img src="..." alt="Warning!" class="icon">
  </div>
  Launch missiles
</button>

This example doesn't use Custom Elements, but you can see that the youngest ShadowRoot is what an x-warning-button would create and the older ShadowRoot is what an x-icon-button would create. The x-warning-button "calls" the x-icon-button using reprojection under the <shadow> (of course it could use <content> outside of the shadow too.)

Some things that DON'T change as a result of this proposal:

1. Nodes are still only output at most once.

2. The algorithm still distributes nodes to all of the <content> elements in one ShadowRoot before "calling" the next oldest ShadowRoot, if any.

You can emulate the old semantics under this new proposal simply by writing

<shadow><content>Fallback content</content></shadow>

provided that all of your <content> selectors outside <shadow> precede it, so they get distributed to first. (I believe there's a separate bug about doing distribution in an author-controlled order, but that deserves a separate discussion.)

This proposal is very flexible and powerful. You could imagine, for example, the x-icon-button actually breaks its functionality up into two ShadowRoots. The oldest one is a "collapser" that flips the Shadow DOM between two trees, one that is just

<content select=".icon-container"></content>

for the collapsed state and another that grabs everything

<content></content>

for the expanded state. This kind of thing isn't possible today because a ShadowRoot in the stack can't introduce anything new to the older ShadowRoot (so, the x-icon-button cannot introduce .icon-holder to the collapser; the x-warning-button cannot introduce the warning icon img to the x-icon-button; etc.) and if you try compete to use something in the host child list (the collapser might try to use the img directly, for example) it will have been "used up" already by the younger one in the stack.

This will make versioning Custom Elements much easier: If x-icon-button gets some embellishment in the future, but maintains backwards-compatible markup API, my x-warning-button won't break, because it is just using that API. This is in contrast to today where you have to be careful not to "touch" anything that the older ShadowRoot is going to output.

FWIW I poked at this in Blink and frankly it will be a hill for us to climb. But I think there is a valley on the other side and the code will ultimately be cleaner because, as Scott says, fundamentally this is just reprojection at work.
Comment 7 Dominic Cooney 2013-06-14 07:23:22 UTC
As an example of how <shadow> breaks encapsulation, the Shadow DOM spec contains this sorry tale:

<https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#html-elements-and-their-shadow-trees>

about exactly what insertion points you can expect a few built-in HTML elements to have. If this proposal is adopted, I don't think that section is necessary any more.
Comment 8 Dimitri Glazkov 2013-06-17 17:17:00 UTC
Since this is a rather dramatic change to the currently spec'd behavior, I would like for everyone to be comfortable with it before we go any farther.

Overall, I like it, and I think there's potential for this to be more intuitive than the old behavior, though I am always worried about the extra complexity. Hayato-san, Morrita-san, WDYT?
Comment 9 Hayato Ito 2013-06-18 04:33:23 UTC
Interesting. Let me read the proposal carefully and add a comment later.
Comment 10 Hayato Ito 2013-06-18 06:33:33 UTC
I've read carefully the proposal.

Looks okay to me. That gives us a more fine controlled way to call *superclass*'s constructor.

For the reference, let me quote the example I've once used to understand this kind of proposal using an Object Oriented analogy.

So far, in the example, the parameters of super(..) are implicit and cannot control.

With the new proposal, we can explicitly specifiy the parameter of super(..) using a notation of '<shadow>parameters</shadow>'.


I've not assessed the feasibility of implementation yet.


---- From Here ----
Custome element: g-flowpanel
  Example markup:
    <g-flowpanel>
      <g-panel/>
      <g-panel/>
    </g-flowpanel>

Custome element: my-flowpanel extends g-flopanel.
  Example markup:
    <my-flowpanel>
      <g-panel/>
      <g-panel/>
      <h3>hello</h3>
    </my-flowpanel>

That might be implemented using the following DOM tree:

  DOM Tree:
  - Shadow Host
    - g-panel
    - g-panel
    - <h3> hello </h3>

  - The older Shadow Root (g-flowpanel)
    - div
      - <content select='gpanel (or something related to gpanel)'>

  - The yonger Shadow Root (my-flowpanel)
      - <content select='h3:first-of-typel'>
      - <shadow>


The following Markup

  <my-flowpanel>
    <g-panel/>
    <g-panel/>
    <h3>hello</h3>
  </my-flowpanel>

corresponds to a constructor's invocation like:

  MyFlowpanel myFlowPanel = new MyFlowPanel(g1, g2, h3);

MyFlowpanel's implementation,

  - The younger Shadow Root (my-flowpanel)
    - <content select='h3:first-of-type'>
    - <shadow>

corresponds to:

  class MyFlowpanel extends GFlowpanel {
    MyFlowPanel(g1, g2, h3) {
      this.h3 = h3
      super(g1, g2);
    }

GFlowpanel's implementation,

  - The older Shadow Root (g-flowpanel)
    - div
      - <content select='gpanel (or something related to gpanel)'>

corresponds to:

  class GFlowpanel extends ??? {
    GFlowPanel(g1, g2) {
      this.g1 = g1;
      this.g2 = g2;
    }


Good analogy are:
  - A <content> element consumes parameters of constructor of parameters like:
    this.x1 = x1
  - A <shadow> element is like calling super class's constructor, like
    'super(...)'. But parameters passed to the super(..) are automatically
    filled. In this case, unselected host's children are passed to the
    super(...).

---- End Here ----
Comment 11 Hayato Ito 2013-06-18 06:42:57 UTC
BTW, the subject of this bug is confusing to me.
I think we should avoid use a term of *projection* here.

Can we have a better name? :)
Comment 12 Dominic Cooney 2013-06-18 06:54:38 UTC
I have attempted to fix the title.

Another way to conceptualize this change is that:

(a) <content> elements descendants of <shadow> elements are eligible for distribution.

(b) <shadow> elements become quasi-hosts of the older ShadowRoot.

This "quasi-ness" raises interesting questions both for web developers (for example, is the context for styles the one surrounding the actual host, or surrounding the <shadow>?--probably the host) and implementers (for example, <shadow> is not rendered, it is really an insertion point; why is this mechanism divorced from display: content/transparent/whatever that proposal is called now?)
Comment 13 Hayato Ito 2013-06-18 07:08:40 UTC
A <shadow> elment should be an insertion point, conceptually. I need this *technique* to make the spec simpler.

I am now trying to update the WIP spec to reflect the proposal in order to find a flaw in the proposal.
https://docs.google.com/document/d/1iuf2DgzwKfMTscAX_xsymO73NmZ4NVYvfyFgUU4YINo/edit#

Let me update this bug when I find a flaw.
Comment 14 Elliott Sprehn 2013-06-18 19:50:27 UTC
I'm not super comfortable having distribution not run in document order. Right now it's forced into O(n) behavior because you start at the top and spread things down. I don't want us to get into situations where you can generate non linear behavior (or need to use tons of memory to avoid doing so).
Comment 15 Dominic Cooney 2013-06-18 22:53:22 UTC
(In reply to comment #14)
> I'm not super comfortable having distribution not run in document order.
> Right now it's forced into O(n) behavior because you start at the top and
> spread things down. I don't want us to get into situations where you can
> generate non linear behavior (or need to use tons of memory to avoid doing
> so).

The reprojection aspect, and not doing distribution in non-document order, has a bigger impact on time. If you're worried about sorting insertion points, do an radix sort. I doubt it matters in practice.
Comment 16 Blake Kaplan 2013-06-19 01:03:32 UTC
I think I'm OK with this proposal, but I'm going to take a couple of days to make sure I really understand this. It seems like the composition algorithm is going to have to change a fair amount because we're no longer distributing in tree order (fwiw, XBL already scans the bindings' DOMs and finds all of the insertion points before distribution).
Comment 17 Hayato Ito 2013-06-19 02:40:09 UTC
I've updated my WIP spec so that it supports the proposal.

https://docs.google.com/document/d/1iuf2DgzwKfMTscAX_xsymO73NmZ4NVYvfyFgUU4YINo/edit?usp=sharing


(In reply to comment #14)
> I'm not super comfortable having distribution not run in document order.
> Right now it's forced into O(n) behavior because you start at the top and
> spread things down. I don't want us to get into situations where you can
> generate non linear behavior (or need to use tons of memory to avoid doing
> so).


We can do in O(n).

Let me quote DISTRIBUTE_POOL algorithm here from the doc.

-- From HERE ---
DISTRIBUTE_POOL(SHADOW_ROOT, POOL) :=
  for each active content element, CONTENT, in SHADOW_ROOT, in tree order:
    for each node, NODE, in POOL:
      if the NODE satisfies CONTENT’s matching criteria:
        DISTRIBUTE_NODE(NODE, CONTENT)
        remove NODE from the POOL
      if insertion-point-to-nodes[CONTENT] is empty:  // [Informative: Fallback]
        for each node, CHILD, in children of CONTENT:
          DISTRIBUTE_NODE(CHILD, CONTENT)
--- END HERE ---


If we encounter an active shadow insertion point in the outer 'for' loop, just remember the position of the active insertion point and skip the traversal of subtree of the active shadow insertion point.
Afte the loop, we continue to distribute POOL to content elements in the subtree of the active insertion point.
That should be done in O(n).


But, I don't like such a hidden rule in general.
> Provided that all of your <content> selectors outside <shadow> precede it, so they get distributed to first. 


My proposal is use 'defer' attribute in content element such as:

> <shadow><content defer></content></shadow>

Like <scrit src='..' defer> is evaluated later, distributing nodes for <content defer> is deferred.
I prefer this explicit approach than an implicit hidden rule.
Comment 18 Dominic Cooney 2013-06-20 01:26:33 UTC
(In reply to comment #17) 
> If we encounter an active shadow insertion point in the outer 'for' loop,
> just remember the position of the active insertion point and skip the
> traversal of subtree of the active shadow insertion point.
> Afte the loop, we continue to distribute POOL to content elements in the
> subtree of the active insertion point.
> That should be done in O(n).

To clarify: What you have written above is a proposal about the order of distribution of <content> elements.

I think your algorithm is confusing because we're also talking about reprojection for <shadow> which would replenish the pool, etc.

> My proposal is use 'defer' attribute in content element such as:
> 
> > <shadow><content defer></content></shadow>

I think we should go for something more flexible like letting the user specify an order. But I would love to know what web developers think.

> Like <scrit src='..' defer> is evaluated later, distributing nodes for
> <content defer> is deferred.
> I prefer this explicit approach than an implicit hidden rule.

I think other proposals are preferable to hard-coding <content> in <shadow> to come last. I can think of cases where you *don't* want content in <shadow> to come last.
Comment 19 Scott Miles 2013-06-20 01:37:06 UTC
I'm having trouble understanding the ambiguity in distribution order that calls for a 'defer' attribute or some other explicit hinting from the developer.

IMO, the developer expects these things to happen in tree order. 

It's possible I just said 'unicorn order' in which case hopefully one of you patient types can point out where there is an ambiguity that I'm missing. =P
Comment 20 Dominic Cooney 2013-06-20 01:45:38 UTC
(In reply to comment #19)
> I'm having trouble understanding the ambiguity in distribution order that
> calls for a 'defer' attribute or some other explicit hinting from the
> developer.
> 
> IMO, the developer expects these things to happen in tree order. 

OK, let's stop talking about distribution order--I'm sorry I brought it up--and focus this bug on distributing into <shadow> and projecting that distribution into the older shadow root.

If anyone wants to discuss distribution order, head on over to bug 22268.
Comment 21 Hayato Ito 2013-06-20 02:34:09 UTC
(In reply to comment #18)
> (In reply to comment #17) 
> > If we encounter an active shadow insertion point in the outer 'for' loop,
> > just remember the position of the active insertion point and skip the
> > traversal of subtree of the active shadow insertion point.
> > Afte the loop, we continue to distribute POOL to content elements in the
> > subtree of the active insertion point.
> > That should be done in O(n).
> 
> To clarify: What you have written above is a proposal about the order of
> distribution of <content> elements.
> 
> I think your algorithm is confusing because we're also talking about
> reprojection for <shadow> which would replenish the pool, etc.

The algorithms in the doc already support the new proposal. There are 4 functions:
  RESOLVE_DISTRIBUTION(TREE_SCOPE)
  POPULATE_CHILDREN_OF(NODE)
  DISTRIBUTE_POOL(SHADOW_ROOT, POOL)
  DISTRIBUTE_NODE(NODE, INSERTION_POINT)

The quoted function, DISTRIBUTE_POOL, is one of the subroutines and a necessary piece to support the new proposal. You can see all functions in section '5 Distributions'.
https://docs.google.com/document/d/1iuf2DgzwKfMTscAX_xsymO73NmZ4NVYvfyFgUU4YINo/edit?usp=sharing

So far, I have succeeded to implement the new proposal in the spec.
I couldn't find any flaw in the new proposal in theory.
I could say that'd be possible as of now.



> 
> > My proposal is use 'defer' attribute in content element such as:
> > 
> > > <shadow><content defer></content></shadow>
> 
> I think we should go for something more flexible like letting the user
> specify an order. But I would love to know what web developers think.
> 
> > Like <scrit src='..' defer> is evaluated later, distributing nodes for
> > <content defer> is deferred.
> > I prefer this explicit approach than an implicit hidden rule.
> 
> I think other proposals are preferable to hard-coding <content> in <shadow>
> to come last. I can think of cases where you *don't* want content in
> <shadow> to come last.
Comment 22 Dominic Cooney 2013-06-21 08:25:35 UTC
So I'd say everyone's temperature is in the range interested-positive?
Comment 23 Hayato Ito 2013-06-24 03:30:24 UTC
I'm positive.

(In reply to comment #22)
> So I'd say everyone's temperature is in the range interested-positive?
Comment 24 Dimitri Glazkov 2013-07-17 19:42:50 UTC
*** Bug 19404 has been marked as a duplicate of this bug. ***
Comment 25 Hayato Ito 2013-07-24 05:03:48 UTC
Fixed. The new distribution algorithm includes this feature.
https://dvcs.w3.org/hg/webcomponents/rev/dbf47f602628
Comment 26 Hayato Ito 2013-07-29 02:26:11 UTC
FYI.
The bug in chromium side is here:
https://code.google.com/p/chromium/issues/detail?id=263701

We've not implemented this feature yet.
Comment 27 Steve Orvell 2013-11-04 22:33:29 UTC
I propose we make:

    <shadow></shadow>

act like this:

    <shadow><content></content></shadow>

Then this change is backwards compatible, and we avoid an extra node in this very common case.

If the author really does not want to distribute elements to a <shadow>, the author would make sure to select them before the <shadow>. This would most likely happen naturally.
Comment 28 Hayato Ito 2013-11-05 02:24:08 UTC
(In reply to Steve Orvell from comment #27)
> I propose we make:
> 
>     <shadow></shadow>
> 
> act like this:
> 
>     <shadow><content></content></shadow>
> 
> Then this change is backwards compatible, and we avoid an extra node in this
> very common case.

Yeah, I once thought that, but I gave up that idea at early stage since it's just like a syntax sugar with a implicit rule.

I don't have strong opinion for that, but that makes the spec complicated. I thought explicit is better than implicit.


> 
> If the author really does not want to distribute elements to a <shadow>, the
> author would make sure to select them before the <shadow>. This would most
> likely happen naturally.
Comment 29 Hayato Ito 2013-11-06 04:00:35 UTC
(In reply to Hayato Ito from comment #28)
> (In reply to Steve Orvell from comment #27)
> > I propose we make:
> > 
> >     <shadow></shadow>
> > 
> > act like this:
> > 
> >     <shadow><content></content></shadow>
> > 
> > Then this change is backwards compatible, and we avoid an extra node in this
> > very common case.
> 
> Yeah, I once thought that, but I gave up that idea at early stage since it's
> just like a syntax sugar with a implicit rule.
> 
> I don't have strong opinion for that, but that makes the spec complicated. I
> thought explicit is better than implicit.

I am aware that migration is painful. I've experienced that when landing the patch in blink. :)
But I still prefer 'explicitly specifying parameters to superclass constructor call'.

I am happy to discuss which is better. I could be convinced.


> 
> 
> > 
> > If the author really does not want to distribute elements to a <shadow>, the
> > author would make sure to select them before the <shadow>. This would most
> > likely happen naturally.
Comment 30 Steve Orvell 2013-11-06 15:52:06 UTC
The main concern is that wanting to distribute elements into <shadow> is the common case. That is arguable, but if we agree then it should be simplest to construct.
Comment 31 Scott Miles 2013-11-06 17:20:10 UTC
I would suggest that this is a clear case where developer ergonomics trumps correctness. 

IOW, where I generally agree that explicit is better, there are times when using an implicit default can flatten the difficulty curve more for users.
Comment 32 Hayato Ito 2013-11-06 23:36:15 UTC
(In reply to Scott Miles from comment #31)
> I would suggest that this is a clear case where developer ergonomics trumps
> correctness. 
> 
> IOW, where I generally agree that explicit is better, there are times when
> using an implicit default can flatten the difficulty curve more for users.

Okay. You have succeeded to convince me. :)

Let me file the new proposal as another bug.

To be precise, A). <shadow></shadow> and B) <shadow><content></content></shadow> is not completely equivalent.

I am going to spec so that the implicit <content> element in case A has the lowest priority in all <content> elements in the tree.

That means case A is similar to "<shadow><content giveMeRemainingNodesAtLast></content></shadow>".
Comment 33 Steve Orvell 2013-11-07 00:36:37 UTC
> That means case A is similar to "<shadow><content giveMeRemainingNodesAtLast>
> </content></shadow>".

I would prefer not to do that and suggest instead that <shadow></shadow> should be equivalent to <shadow><content></content></shadow>.

In the interest of 'keeping it simple', we should avoid inventing a new priority for <content> that's only applicable in this case.
Comment 34 Hayato Ito 2013-11-07 00:51:20 UTC
(In reply to Steve Orvell from comment #33)
> > That means case A is similar to "<shadow><content giveMeRemainingNodesAtLast>
> > </content></shadow>".
> 
> I would prefer not to do that and suggest instead that <shadow></shadow>
> should be equivalent to <shadow><content></content></shadow>.
> 
> In the interest of 'keeping it simple', we should avoid inventing a new
> priority for <content> that's only applicable in this case.

Okay, but I prefer "<shadow><content giveMeRemainingNodesAtLast></content></shadow>" for the following reasons:

1. It doesn't break a backward compatibility and matches the behavior of old <shadow> element.

2. I'm afraid that consuming all nodes by a hidden <content> element is *too* implicit and is not flexible for users. For example, the following case doesn't work and the result might be against user's intention:

  #shadow-root
     <content id=a select=".header"></content>
     <shadow id=b></shadow>
     <content id=c select=".footer"></content>
Comment 35 Steve Orvell 2013-11-07 03:22:38 UTC
With the new semantics, the old <shadow> behavior of 'giveMeRemainingNodesAtLast' is just gone, so even though it would maintain backward compatibility, I think making an empty <shadow> work this way will just be confusing going forward since an empty <shadow> would be the *only* way to get that exact functionality.

We should view 'empty <shadow> acts as if it contains a <content>' as only a shorthand for the common case, adding no different behavior than if you took the time to type that out by hand. This way it's very easy to explain.
Comment 36 Hayato Ito 2013-11-07 04:25:35 UTC
(In reply to Steve Orvell from comment #35)
> With the new semantics, the old <shadow> behavior of
> 'giveMeRemainingNodesAtLast' is just gone, so even though it would maintain
> backward compatibility, I think making an empty <shadow> work this way will
> just be confusing going forward since an empty <shadow> would be the *only*
> way to get that exact functionality.
> 
> We should view 'empty <shadow> acts as if it contains a <content>' as only a
> shorthand for the common case, adding no different behavior than if you took
> the time to type that out by hand. This way it's very easy to explain.

Thank you. We have different opinions. I am happy to discuss!

But this time, I guess you have difficult time to convince me. :)

Let's forget "<shadow><content giveMeRemainingNodesAtLast></content>". I am feeling that this is not good explanation because it unnecessarily highlights a phantom content element, which doesn't appear in code.

Instead of that, let's call my proposal, the rule of "An empty shadow insertion point takes all remaining nodes".

- This rule satisfies the most common use cases which developers want. Users don't have to be afraid whether a <content> element comes after the shadow insertion point or not. Developers can put a shadow insertion point anywhere.

If a shadow insertion point acts like <shadow><content></content></shadow>, I am afraid that developers have to be careful about the position of the shadow insertion point. For example, when the following tree is given:

A)
 #shadow-root
     <content id=a select=".deco1"></content>
     <content id=c select=".deco2"></content>
     <shadow id=b></shadow>

If developers want to change the position of the shadow insertion point as follows:

B)
 #shadow-root
     <content id=a select=".deco1"></content>
     <shadow id=b></shadow>
     <content id=c select=".deco2"></content>

This doesn't work because the shadow insertion point eats all nodes, including '.deco2'.
Instead of B), developers have to write:

C)
 #shadow-root
     <content id=a select=".deco1"></content>
     <shadow id=b><content select=":not(.deco2)"></content></shadow>
     <content id=c select=".deco2"></content>

Unfortunately, according to the matching criteria (https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#satisfying-matching-criteria), developers cannot write easily such a select attribute (because :not is a pseudo class), can we? The current support for selectors used by content insertion points is too weak to achieve C.



- For explanation, I think all we have to say is "an empty shadow insertion point takes all remaining nodes". That's easy to explain, isn't it? Actually, this rule makes the spec and the implementation simpler than a hidden <content> element, as far as I've tried so far.
Comment 37 Scott Miles 2013-11-07 04:43:07 UTC
Your A, B, and C are true for anything that re-projects. IOW, if you replace <shadow> with <x-foo> you have all the same scenarios and there is no magic escape hatch. Similarly, if you remove re-projection from the example and use only content nodes, position is still semantically relevant and one must be conscious of it.

From that standpoint, I don't see why <shadow> should have different behavior.

If we were to solve that problem more generally, that would make more sense to me. E.g. if we introduce a special selector to mean "leftovers".  We have users asking for this already.

I realize that our request for an 'implicit content' in <shadow> is also exceptional, and I'm arguing against exceptions, but that exception is only for syntactic sugaring and is not a new semantic.
Comment 38 Hayato Ito 2013-11-07 05:18:30 UTC
(In reply to Scott Miles from comment #37)
> Your A, B, and C are true for anything that re-projects. IOW, if you replace
> <shadow> with <x-foo> you have all the same scenarios and there is no magic
> escape hatch. 

Thank you! But I am afraid that I don't fully understand what this means. Could you help me to understand?
Comment 39 Scott Miles 2013-11-07 06:22:26 UTC
Sorry I didn't explain myself very well, thank you for your patience.

Take this example from your post:

     <content select=".deco1"></content>
     <shadow><content select=":not(.deco2)"></content></shadow>
     <content select=".deco2"></content>

As you say, we cannot use :not, so this is no good. 

But, if we write this:

     <content select=".deco1"></content>
     <div><content select=":not(.deco2)"></content></div>
     <content select=".deco2"></content>

or this

     <content id=a select=".deco1"></content>
     <x-foo><content select=":not(.deco2)"></content><x-foo>
     <content id=c select=".deco2"></content>

neither of those cases work either for the same reason.

Providing a "leftovers" convention for no-content <shadow> solves the first case, but doesn't help either of the other cases. To my mind, that suggests it's not worth the cost of being special.

Today, what we say is that you must do this:

     <content id=a select=".deco1"></content>
     <content id=c select=".deco2"></content>
     <content></content>

And use CSS if you need rearrange the nodes for presentation.

As I mentioned, we could invent a special "leftovers" selector, then we could do something like this:

     <content select=".deco1"></content>
     <content select="!leftovers!"></content>
     <content select=".deco2"></content>

and that would solve all three cases.

However, there are similar cases that require ordering that are not rescued by a "leftovers" semantic, e.g.:

     <content select=".deco"></content>
     <content select="span"></content>

If there are some spans that have .deco then the ordering of nodes is again relevant and we must use CSS to re-arrange for presentation.

I hope that's a bit clearer? Thanks for all your work on these issues!
Comment 40 Hayato Ito 2013-11-07 07:07:20 UTC
I understand. Thank you!
But I don't think the fact of "we don't have a leftover attribute for a content element yet" is a blocking issue for *my* <shadow>.

To rescue every cases, suppose that we will implement 'leftover (tentative name)' attribute for a <content> element eventually.
We have several choices how we proceed in what orders:


Plan A)
1. Make '<shadow></shadow>' act like '<shadow><content leftover></content></shadow>'.
2. Support a 'leftover' attribute for a <content> element.


Plan B)
1. Make '<shadow></shadow>' act like '<shadow><content></content></shadow>'.
2. Support a 'leftover' attribute for a <content> element.
3. Make '<shadow></shadow>' act like '<shadow><content leftover></content></shadow>'.


Plan C)
1. Make '<shadow></shadow>' act like '<shadow><content></content></shadow>'.
2. Support a 'leftover' attribute for a <content> element.
3. That's all. (We won't make <shadow></shadow> act like <shadow><content leftover></content></shadow>).


I am proposing Plan A, rather than Plan B or Plan C. In other words, I think it's okay that we have some amount of time between  A-1 and A-2. Does it sound reasonable? 

I am not sure which plan is best for us. Do you prefer Plan B, Plan C, or any other plan?
Comment 41 Scott Miles 2013-11-07 07:18:38 UTC
Starting with the concept that "leftover" itself, in any form, only solves a subset of cases, I suggest that it be a completely separate feature, and not related to this question of <content> in <shadow>.

This way we can completely decouple (and defer) the feature request about prioritizing <content> explicitly, instead of relying on tree-order.

Then I go back to what is implemented today, which IIRC, is that all the following behave consistently:

<shadow><content></content></shadow>
<x-foo><content></content></x-foo>
<div><content></content></div>

Then I take only one more step, which is to suggest that <shadow> would benefit from a bit of syntactic sugar: the ability to write

<shadow></shadow>

and have it work as if I wrote

<shadow><content></content></shadow>

That's my $0.02. :)
Comment 42 Hayato Ito 2013-11-07 08:02:01 UTC
Thank you! I understand your argument.

But, at this point, I don't think there is a strong reason for '<shadow></shadow>' should be equivalent to '<shadow><content></content></shadow>'.

Let me explain my feeling:

- Forget <content>! Let's make '<shadow></shadow>' behave nicely! A <shadow> element is already so special. It's okay that there is no equivalent syntax for <shadow></shadow>. We will get real benefits from it! Yay!

:)
Comment 43 Steve Orvell 2013-11-07 15:24:41 UTC
I alsot see the 'leftover' problem as separate. In fact there is another bug for it: 

https://www.w3.org/Bugs/Public/show_bug.cgi?id=22268

I would suggest that Hayato-san's concerns about <shadow> are important and should be solved in that context. In particular, if empty <shadow> (that acts as if it has a <content> inside it) is problematic, then isn't <shadow><content></content></shadow> equally problematic?
Comment 44 Hayato Ito 2013-11-08 04:50:59 UTC
I've filed a bug in https://www.w3.org/Bugs/Public/show_bug.cgi?id=23767

Let me try to spec it and see how it goes well.