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 21886 - [Custom]: Define or link to what it means for a local name to be associated with an interface
Summary: [Custom]: Define or link to what it means for a local name to be associated w...
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC Linux
: P2 normal
Target Milestone: ---
Assignee: Dimitri Glazkov
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 18720
  Show dependency treegraph
 
Reported: 2013-05-01 03:06 UTC by Dominic Cooney
Modified: 2013-05-30 22:16 UTC (History)
5 users (show)

See Also:


Attachments

Description Dominic Cooney 2013-05-01 03:06:36 UTC
In the steps for register, the spec opines thus: "If BASE is not HTMLElement or SVGElement, let NAME be the local name, associated with BASE element interface"

However HTMLModElement is associated with INS and DEL.

What would the meaning of this be?

X = document.register('x-foo', {
  prototype: HTMLModElement.prototype
});
(new X).outerHTML

<ins is="x-foo"></ins>

and

<del is="x-foo"></del>

are equally plausible.
Comment 1 Dimitri Glazkov 2013-05-07 21:00:59 UTC
Two paths here:

1) provide a tag hint ("extends") as document.register argument
2) pick one (with an explicit list of what's being picked)

WDYT?
Comment 2 Dominic Cooney 2013-05-08 00:25:23 UTC
(In reply to comment #1)
> Two paths here:
> 
> 1) provide a tag hint ("extends") as document.register argument
> 2) pick one (with an explicit list of what's being picked)
> 
> WDYT?

1) Is nice because it lines up with the proposals for <element> that I saw.

2) Is nice because it gives a meaning to the above example even if the developer did not write 'extends.'

Do we need both, and use #2 as a fallback if #1 is not specified?
Comment 3 Blake Kaplan 2013-05-16 20:20:16 UTC
I like the idea of an explicit tag "hint" since it's less magic and, in general, I like more explicitness. Also, us randomly choosing e.g. <ins> over <del> seems totally arbitrary to me.

I'm tempted to suggest that for unambiguous prototypes (e.g. HTMLVideoElement) that we do the magic "divine the localName from the prototype" (which would be option 2, I guess) but do we have to worry about new elements breaking existing document.register calls by adding a new built-in element that would make a previously-unambiguous call to document.register ambiguous?
Comment 4 Dominic Cooney 2013-05-17 00:00:11 UTC
Proposal A: Any type extension needs to name a tag when it is registered, even if it is redundant based on the prototype.

This has some nice aspects:

- It's clearer when you're registering a type extension and when you're registering a custom tag, which is a plus.

- Maybe we could not bother doing prototype chain walking on register. If the author wants to mess up prototype chains, let them.

(In reply to comment #3)
> I'm tempted to suggest that for unambiguous prototypes (e.g.
> HTMLVideoElement) that we do the magic "divine the localName from the
> prototype" (which would be option 2, I guess) but do we have to worry about
> new elements breaking existing document.register calls by adding a new
> built-in element that would make a previously-unambiguous call to
> document.register ambiguous?

There's also the question of whether doing something ambiguous like extending HTMLModElement, HTMLHeadingElement. Is that an error?

Proposal B: 

1. Each HTML element has an associated tag name. Those are per the HTML spec, except in the case of HTMLModElement, HTMLHeadingElement (others?) which are defined to be "ins" and "h1" respectively. (Yes, it is arbitrary.) This future proofs existing kinds of elements that gain a new tag name; we can just define their associated tag name post-hoc to be whatever the historical name was.

2. document.register's dictionary argument has another optional entry (what should we call it?) that specifies the tag name the element should have *when created by the constructor*.

3. createElement, createElementNS aren't changed. The author can use any matching tag name for those calls.

Some code to illustrate this suggestion:

var A = document.register('x-a', {prototype: Object.create(HTMLHeadingElement.prototype)});

var h3 = document.createElement('h3', 'x-a');
Object.getPrototypeOf(h3) === A.prototype  // true per #3 above

(new A).outerHTML // "<h1 is="x-a"></h1> per #1 above

var B = document.register('x-b', {prototype: Object.create(HTMLHeadingElement.prototype}, localName: 'h4'});

(new B).outerHTML // "<h4 is="x-b"></h4> per #2 above

var h2 = document.createElement('h2', 'x-b');
Object.getPrototypeOf(h2) === B.prototype  // true per #3 above

Making this go would require rework to DEFINITION which only has one name in it. Not sure how much behavior is hooked off that.

I think both Proposal A and Proposal B are consistent. I like Proposal A; it looks simpler and more predictable.
Comment 5 Blake Kaplan 2013-05-17 22:35:20 UTC
(In reply to comment #4)
> - Maybe we could not bother doing prototype chain walking on register. If
> the author wants to mess up prototype chains, let them.

wchen pointed out to me recently that because prototype chains are mutable, doing any sort of checking under document.register only gives hints to the authors at best. At worst, it prevents some overly-clever author from doing what he wants. Given that and the ambiguous prototype problem, it seems like we should basically just ignore the prototype for the purposes of document registration (except to associate the name with the prototype).

> There's also the question of whether doing something ambiguous like
> extending HTMLModElement, HTMLHeadingElement. Is that an error?

It would have to be. I really don't like the magical "guess the name" APIs in general. Proposal A seems like the way to go.
Comment 6 Dimitri Glazkov 2013-05-21 22:10:32 UTC
(In reply to comment #5)
> It would have to be. I really don't like the magical "guess the name" APIs
> in general. Proposal A seems like the way to go.

If we're going with A, should the base element name be:

1) the second optional argument in document.register. The drawback here is that for some values of options.prototype, the argument is _not_ optional, which is somewhat confusing.

2) another option of ElementRegistrationOptions. The drawback here is that in ES6, this will be just a static class member, and then people will be asking, "why is that here?" And "why isn't name there as well?"

Also adding Scott, who comes with opinions.
Comment 7 Dominic Cooney 2013-05-22 02:56:17 UTC
(In reply to comment #6)
> If we're going with A, should the base element name be:
> 
> 1) the second optional argument in document.register. The drawback here is
> that for some values of options.prototype, the argument is _not_ optional,
> which is somewhat confusing.

OK, what about this:

There are two overloads of document.register. The first is for custom tags:

register(DOMString tagName, ElementRegistrationOptions options)

The second is for type extensions:

register(DOMString tagName, DOMString type, ElementRegistrationOptions options)

So this would look like:

document.register('x-panel', Panel)
document.register('button', 'accessible-button', AccessibleButton)

If you hate overloads you could make the first argument selector-like, eg 'x-panel', 'button[is=accessible-button]'.

> 2) another option of ElementRegistrationOptions. The drawback here is that
> in ES6, this will be just a static class member, and then people will be
> asking, "why is that here?" And "why isn't name there as well?"

You could use localName on the prototype. That will shadow the built-in one, though, which is a wart. And the author might expect that they can change it, which they can't.
Comment 8 Dimitri Glazkov 2013-05-22 21:08:26 UTC
(In reply to comment #7)
> There are two overloads of document.register. The first is for custom tags:
> 
> register(DOMString tagName, ElementRegistrationOptions options)
> 
> The second is for type extensions:
> 
> register(DOMString tagName, DOMString type, ElementRegistrationOptions
> options)
> 
> So this would look like:
> 
> document.register('x-panel', Panel)
> document.register('button', 'accessible-button', AccessibleButton)

I am okay with this. Going once...
Comment 9 Scott Miles 2013-05-22 21:13:16 UTC
The nominal reason the last argument is a dictionary is to allow this kind of API expansion, correct?

We are being clever with the 'can be a dictionary-with-prototype OR a class' trick, but it seems less than ideal to have that affect the design.

In particular, if we come up with some other option, do we overload the API further?

For these reasons, I'd be more inclined to let those options be static members on the class.
Comment 10 Dominic Cooney 2013-05-22 22:51:53 UTC
(In reply to comment #9)
> The nominal reason the last argument is a dictionary is to allow this kind
> of API expansion, correct?

Yes.

> We are being clever with the 'can be a dictionary-with-prototype OR a class'
> trick, but it seems less than ideal to have that affect the design.
> 
> In particular, if we come up with some other option, do we overload the API
> further?

Case-by-case, I assume.

FWIW in the implementation in Blink a lot bifurcates on whether the custom element is a type extension or a custom tag. A similar situation might arise in scripts using document.register--you're either doing one or the other at any given point.

> For these reasons, I'd be more inclined to let those options be static
> members on the class.

This is also fine from an implementor's point of view.
Comment 11 Dimitri Glazkov 2013-05-22 22:58:20 UTC
Should we then just get rid of the first argument, as well?

document.register({
   name: 'awesome-sauce',
   extends: 'button',
   prototype: ...
});

document.register(class AwesomeSauce : HTMLButtonElement {
  static name = 'awesome-sauce';
  static extends = 'button';
  ...
});
Comment 12 Blake Kaplan 2013-05-22 23:09:06 UTC
(In reply to comment #11)
> Should we then just get rid of the first argument, as well?

Given that the name has to be passed no matter what (and that will be the case no matter what new language features show up in the future) I think it still makes sense to pass it separately, but I don't feel strongly about that. Otherwise, this proposal seems fine to me.
Comment 13 Dimitri Glazkov 2013-05-29 23:00:28 UTC
(In reply to comment #12)

There's one somewhat nasty effect of this(In reply to comment #5)
> (In reply to comment #4)
> > - Maybe we could not bother doing prototype chain walking on register. If
> > the author wants to mess up prototype chains, let them.
> 
> wchen pointed out to me recently that because prototype chains are mutable,
> doing any sort of checking under document.register only gives hints to the
> authors at best. At worst, it prevents some overly-clever author from doing
> what he wants. Given that and the ambiguous prototype problem, it seems like
> we should basically just ignore the prototype for the purposes of document
> registration (except to associate the name with the prototype).

Just to keep my sanity and record this somewhere. There's a fun discord between that explicit hint value (let's call it "type extension base value") and the value of "extends" attribute in the declarative syntax:

1) The type extension base value is always identifying a built-in HTML/SVG element.
2) The extends value could be both a built-in and custom element name.
Comment 14 Dimitri Glazkov 2013-05-29 23:30:10 UTC
(In reply to comment #5)
> (In reply to comment #4)
> > - Maybe we could not bother doing prototype chain walking on register. If
> > the author wants to mess up prototype chains, let them.
> 
> wchen pointed out to me recently that because prototype chains are mutable,
> doing any sort of checking under document.register only gives hints to the
> authors at best. At worst, it prevents some overly-clever author from doing
> what he wants. Given that and the ambiguous prototype problem, it seems like
> we should basically just ignore the prototype for the purposes of document
> registration (except to associate the name with the prototype).

We still need to do some prototype chain walking, because we need to infer the namespace for the custom element (it really is either HTML or SVG namespace).
Comment 15 Dominic Cooney 2013-05-30 00:53:41 UTC
(In reply to comment #14) 
> We still need to do some prototype chain walking, because we need to infer
> the namespace for the custom element (it really is either HTML or SVG
> namespace).

I think the spec should only allow type extensions for SVG. Then all custom tags will be HTML and no prototype walking is required.

My thinking is this: SVG basically gives up when it encounters an unknown element (it doesn't render that element's children, for example.) Assuming you're using SVG to draw something, you're gonna want to use a specific tag (at least <g>, which is a nice neutral one.)

If you think custom tags are important to SVG, perhaps we should define custom tags to be extensions of SVGGElement (ie <g>, note the extra G) and not SVGElement?
Comment 16 Dimitri Glazkov 2013-05-30 22:16:08 UTC
Whew, this was way too much work than I anticipated.

https://dvcs.w3.org/hg/webcomponents/rev/453121760f2a