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 21485 - [Custom]: Consider possible candidates of element upgrade
Summary: [Custom]: Consider possible candidates of element upgrade
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Dimitri Glazkov
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 18720
  Show dependency treegraph
 
Reported: 2013-04-01 06:21 UTC by Morrita Hajime
Modified: 2013-04-23 22:38 UTC (History)
6 users (show)

See Also:


Attachments

Description Morrita Hajime 2013-04-01 06:21:49 UTC
TL;DR:
Current upgrade algorithm isn't perfect
but better than possible alternatives in my mind.

Moved discussion from [1].
Current upgrade algorithm [2] does the upgrade only in-document elements.
This means that any out-of-document element which has becomes-valid name
doesn't get upgraded. For example:

  var outOfDocElement = document.createElement("x-foo");
  document.register("x-foo", ...);
  // a) Here |outOfDocElement| doesn't get any upgrade.
  document.body.appendChild(outOfDocElement);
  // b) It won't be upgraded even after inserted into document.

This might be confusing and inconvenient for developers so
it's worth exploring better approach.

Here are three alternative approaches:

- A: Upgrade all elements regardless they are in the document.
- B: Current algorithm +
     Upgrade "yet-to-be-upgraded" elements when it is inserted into the document.
- C: Current algorithm +
     Provide document.upgrade(element) API for explicit upgrade.

Approach A might be straightforward from developers' perspective.
However, it requires implementations to track all unresolved elements, which is bad IMO. 

How about B? It seems natural extension of A.
B raises an interesting question though: What does happen when a custom element,
which lives in a document D1, is inserted to different document D2,
which has different custom element definition on same element name?

Should the element be "upgraded" to D2's definition? Or should it stay D1's definition?
I think this complication comes from the idea to tie the element definition and document closures.

C just exposes the upgrade algorithm to developers and let them handle it in the way they want.
This might just work. But I feel it a premature fine-tuning and want to let us go without it
and see what developers find.

In summary, each alternative has its own caveats and current behavior is the best preferable
due to its simplicity.

----
[1] https://bugs.webkit.org/show_bug.cgi?id=113362
[2] https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-element-upgrade
Comment 1 Scott Miles 2013-04-01 16:58:36 UTC
My initial reactions:

I could live in a world where outOfDocElement is simply never upgraded; in general I'm willing to accept some resposibility for timing of actions. From this standpoint, it's all a matter of how costly each option is to implement.

A. upgrade all: is probably best, but since Morrita-san says it causes trouble, I'm ready to dismiss it.
B. upgrade on insertion: would probably be a good compromise.
C. document.upgrade(): my sense is to avoid this complication.
D. do nothing: simple may be best, as suggested.

>> What does happen when a custom element, which lives in a document D1, is inserted to different document D2 <<

IMO, nothing at all. I suspect user wants the behavior element had in D1 to be transferred to D2. I realize this creates a weird situation wrt localName. I would rather somehow alter localName then morph the element. Another possibility is to just make it an error.
Comment 2 Boris Zbarsky 2013-04-01 17:11:34 UTC
> IMO, nothing at all.

That's not compatible with the prototype chain reparenting UAs do in practice when transferring elements between documents, fwiw.

> Another possibility is to just make it an error.

This is .... somewhat nontrivial, actually.  Unless you make all adopt operations do an extra pass over the to-be-adopted tree just in case it has components in it or something.
Comment 3 Scott Miles 2013-04-01 17:19:39 UTC
> That's not compatible with the prototype chain reparenting UAs do in practice when transferring elements between documents, fwiw.

In that case, I don't see how we avoid completely tearing down the element and then rebuilding it in the new document. IOW, shadow-dom and user initializations wil vary by registration.
Comment 4 Boris Zbarsky 2013-04-01 17:22:55 UTC
I don't see it either, frankly.  Pretty sure that's what happens in Gecko's current implementation, in fact.
Comment 5 Scott Miles 2013-04-01 17:28:31 UTC
> Pretty sure that's what happens in Gecko's current implementation,
> in fact.

Sorry if this is naiive, but we couldn't just throw an exception about incompatible registrations at this point?
Comment 6 Boris Zbarsky 2013-04-01 17:44:34 UTC
At what point?

Currently, calling adoptNode on a node adopts the entire subtree rooted at that node.

Adopting part of the subtree and then throwing an exception seems like a really bad idea, because then you get a subtree of nodes which have different ownerDocuments, which can't ever really happen.  In fact, it's a bad enough idea that if that situation ever happens (which it can't per spec right now, note) Gecko disconnects every single node in the subtree from all the other nodes before throwing an exception...
Comment 7 Scott Miles 2013-04-01 17:51:30 UTC
All I'm noticing is that you said:

> extra pass over the to-be-adopted tree just in case it has components in it

but then we agreed that components [custom elements] have to be detected and handled specially during adoption anyway.

If you say the latter doesn't remove the necessity for the former, 
then I take it as read.
Comment 8 Boris Zbarsky 2013-04-01 17:54:13 UTC
The point is that throwing during the middle of adoption is really bad, so you have to throw _before_ you start adopting, which means you need to prescan for custom elements or something.
Comment 9 Scott Miles 2013-04-01 17:57:17 UTC
Ok, thank you for zeroing in on that for me.
Comment 10 Scott Miles 2013-04-01 18:10:48 UTC
Wrt outOfDocument element, I realize I'm not clear on the state of elements in 'imported' documents, and elements inside of <template>.

It's standard procedure for us to do things like this:

<template>
  <x-custom></x-custom>
</template>
<script>
  otherDom.appendChild(template.createInstance());
</script>

At what point is x-custom upgraded? 

Additionally, what if the above code is in an 'imported' document (<link rel='import'>)?

I realize our polyfill(s) don't handle this at all, and our sugaring layer specifically upgrades all custom elements after they are instanced from a template. Seems like I sidestepped this problem in my own thinking.

Scott
Comment 11 Scott Miles 2013-04-01 18:26:07 UTC
I apologize, I was imprecise above.

There can be custom elements inside of 'imported' documents. Do imported documents share the element registry? 

If so, then I suppose there is no problem with transferring nodes from imported document, or cloning nodes from imported document, and inserting them into the main document.

Presumably, template stamping is a version of subtree cloning. Nodes in a template are in a document fragment, I believe. Does the fragment share the element registry? The template may also be in a linked document, so the content may be twice removed.

If the registries are not shared, then custom elements would have to be 'upgraded' on insertion into the new document.

I hope that's clearer.
Comment 12 Scott Miles 2013-04-01 23:34:26 UTC
Dimitri was asked directly about 'sharing registries' and he said he thought 'no'.

On reflection, I believe this actually is the only answer that makes sense, but it requires:

B: Current algorithm + Upgrade "yet-to-be-upgraded" elements when 
   it is inserted into the document.

Examples below are given in terms of <template> because it's encapsulating document shenanigans, but I believe this is WLOG to doing it by hand.

Example:

<template>
   <x-foo></x-foo>
</template>

<x-foo> lives in a document fragment with no definition of x-foo, so it is 'plain'. The only chance then to upgrade x-foo is when I insert it into the 
main document.

This is sane, because it would be wasteful to upgrade <x-foo> in the document fragment (it must be inert, after all) and in any case it would need to be 'custom-cloned' (i.e. re-initialized).

I believe this would work similarly for imports.
Comment 13 Boris Zbarsky 2013-04-02 01:02:11 UTC
> The only chance then to upgrade x-foo is when I insert it into the
> main document.

Insert, or adopt?  In that situation, upgrading on adopt, as long as upgrading can't fail, would be quite easy to do.

So this situation is somewhat orthogonal to what happens for nodes that already have the same ownerDocument and then get inserted somewhere.
Comment 14 Scott Miles 2013-04-02 01:10:50 UTC
An alternative notion has been floated that could work with answer 'A'.

The idea is that when, e.g., templates are instantiated, the correct node is generated at creation time (as long as the nodes are created with the proper document owner).

I believe the advantage of this idea is that upgrade is decoupled from adoption/insertion.

In the general case however, cloneNode has no notion of 'target document' to make this work. I also expect users to want to migrate subtrees from imports to the main document, and expect the custom elements to generate.

Sidebar: the notion of A may require that some custom elements take care to operate only on insertion, and even then only in suitable contexts. I don't claim this is a problem however, because this is a normal condition for DOM nodes. For example, <img src='foo.jpg'> tag doesn't actually hit the network to load 'foo.jpg' until it's in a suitable document context.
Comment 15 Boris Zbarsky 2013-04-02 01:23:54 UTC
> For example, <img src='foo.jpg'> tag doesn't actually hit the network to load
> 'foo.jpg' until it's in a suitable document context.

That's a particularly bad example, because whether <img> does the load depends only on its ownerDocument and not on anything else.
Comment 16 Morrita Hajime 2013-04-02 06:55:28 UTC
(In reply to comment #2)
> > IMO, nothing at all.
> 
> That's not compatible with the prototype chain reparenting UAs do in
> practice when transferring elements between documents, fwiw.
> 

I wasn't aware of reparenting thing. Is this part of DOM standard?
I tried it http://jsfiddle.net/4gxHQ/1/ and see neither Chrome and Safari does but Firefox.

If Chrome adopts this reparenting behavior, B possibly can be an extension of such reparenting.
Comment 17 Boris Zbarsky 2013-04-02 14:40:51 UTC
> Is this part of DOM standard?

It's being discussed.

> and see neither Chrome and Safari does

Actually Safari sometimes does and sometimes doesn't, in a gc-dependent way.  It's quite lovely.
Comment 18 Dimitri Glazkov 2013-04-02 17:21:34 UTC
(In reply to comment #17)
> > Is this part of DOM standard?
> 
> It's being discussed.
> 
> > and see neither Chrome and Safari does
> 
> Actually Safari sometimes does and sometimes doesn't, in a gc-dependent way.
> It's quite lovely.

The discussion is here: 

http://lists.w3.org/Archives/Public/www-dom/2012OctDec/thread.html#msg143 and
http://lists.w3.org/Archives/Public/www-dom/2013JanMar/thread.html#msg67
Comment 19 Rafael Weinstein 2013-04-02 21:51:29 UTC
So it seems to me that the *most* sanity results from the strongest guarantee:

->Script should never have access to an un-upgraded custom element.

Deviation from this invariant exposes a fracture in the mental model that page script may implement host (DOM) elements.

This invariant is unachievable, as demonstrated in Morrita-san's original example. I.e. since registration can happen at any time, script will always have access to an un-upgraded element before it was registered.

However, a slightly less strong guarantee *is* possible:

->Script should never have access to an un-upgraded custom element, once the identity of that element is known (i.e. it has been registered).

In my mind, anything short of this is a serious flaw in the processing model of custom elements and falling short should have strong justification.
Comment 20 Rafael Weinstein 2013-04-02 22:28:49 UTC
Also, WRT To <template> contents, the question arises: should template contents also be upgraded?

Given that <template> is the primitive for expressing prototypes of DOM fragments -- and script is very likely to interact with those elements, the desirability of a strong guarantee about custom element upgrade necessarily extends to template contents.

At worst, the upgrade algorithm (https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-element-upgrade) to should upgrade all elements which are a host-including inclusive ancestor (http://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor) of the document.
Comment 21 Scott Miles 2013-04-02 22:56:03 UTC
Rafael's argument is compelling to me, so I guess I would revise my answer to be A.

> Dimitri was asked directly about 'sharing registries' and he said he thought 
> 'no'.

I think for A to work, we have to have some sharing of registries.
Comment 22 Scott Miles 2013-04-02 23:00:16 UTC
And we are also prepared to accept the notion from my 'sidebar' above that custom elements will need to take care about what context they are in before taking action (specifically in _readyCallback_).

I'm being vague because previously I used a bad example ('img'), but I think the bottom line is that a custom element would be advised to test 'ownerDocument.defaultView' in some cases.
Comment 23 Morrita Hajime 2013-04-04 05:52:56 UTC
Putting aside cross-document thing, I'm OK to take A.

It might be surprising for developers to have such side effect to out-of-document elements, but I agree that it results better invariant as Raphael pointed.

For cross document (custom) element adoption, we need to align HTML Imports definition where external custom elements and many <template>s are defined. And taking A, this can be discussed in perfectly orthogonal way.

So should the summary of this bug be something like "Out-of-document elements should be upgraded"?
Comment 24 Rafael Weinstein 2013-04-04 16:07:19 UTC
+1.

I think it's far more surprising that out of document elements would not be upgraded.
Comment 25 Dimitri Glazkov 2013-04-22 22:29:00 UTC
Re-reading this, I am convinced that we should upgrade all elements whose ownerDocument is the document with which we register the new element.
Comment 26 Dimitri Glazkov 2013-04-23 22:38:54 UTC
https://dvcs.w3.org/hg/webcomponents/rev/9a2f50cedba0
https://dvcs.w3.org/hg/webcomponents/rev/4e93030dfed7

Now moar better. All elements are upgraded, whether in tree or not.

Please look over the spec and let me know if I goofed up anything.