On 1/9/15 8:01 PM, Domenic Denicola wrote:
I was writing up my ideas in an email but it kind of snowballed into something
bigger so now it's a repo: https://github.com/domenic/element-constructors
Domenic, thanks for putting this together.
Caveat: I won't get a chance to read through this carefully until
Monday. Responses below are based on just what's in the mail.
That said, I do have one question already: what does the term
"own-instances" mean in that document?
whether it is acceptable to have an element whose name is "a", namespace is the
HTML namespace, and interface is Element
I'd like to understand what you mean by "interface is Element" here,
exactly.
One ugly point of my design is that the constructor signature is `new
Element(localName, document, namespace, prefix)`, i.e. I require the document
to be passed in. I am not sure this is necessary
It's necessary, but I think the document should be allowed, but not
required. As in, the signature should be:
new Element(localName, namespace, prefix, document).
(though maybe prefix should come after document; hard to say). If the
document is undefined, then we get a document as follows: Element is a
function, so has an associated Realm. This Realm's [[globalThis]] is a
Window. This Window has a .document; use that.
The only reason we need the ability to specify a document at all is that
there are documents around that are not inside a browsing context (XHR
responseXML, for example) and we need to be able to create elements that
have those documents as an ownerDocument. But those document's don't
have their own global/Realm and hence don't have separate instances of
the Element constructor.
I commented on the github issue in a bit less detail.
what is the use case for producing something that extends HTMLImageElement (and
presumably has its internal slots?) but doesn't have "img" as the tag name and
hence will not have anything ever look at those internal slots?
Elsehwere on this thread or some related one IIRC he pointed out code that looks at the local name, finds
"img", and casts to the C++ backing representation of HTMLImageElement. So from what I am
gathering in his view the parts of the platform that treat <img> elements specially currently work
by checking explicitly that something has local name "img" (and HTML namespace).
Yes. And that's true of not just implementations but also
specifications. The entire HTML specification is written in terms of
local name tests, for example.
From a naïve authoring point of view that seems suboptimal. I'd rather be able to do
`class MyImg extends HTMLImageElement { constructor(document) { super(document); } }` and
have MyImg instances treated specially by the platform in all the ways "img"
currently is.
I don't quite see the issue here. Presumably the HTMLImageElement
constructor passes "img" as the localName to the HTMLElement
constructor, so your MyImg would get "img" as the localName, right?
Can you explain what the concern is here?
Now I do think there's an authoring problem where if you want to do a
<fancyimage> that's treated like <img> by the platform you have a
problem. But that doesn't seem to be what you're talking about... or
are you?
Or, for an easier example, I'd like to be able to do `class MyQ extends HTMLQuoteElement
{ constructor(document) { super(document); } }` and have `(new MyQ()).cite` actually
work, instead of throw a "cite getter incompatible with MyQ" error because I
didn't get the HTMLQuoteElement internal slots.
This should totally work, of course. Why wouldn't it, exactly? Given
the subclassing proposal on the table in ES6 right now, it would work
splendidly, since the HTMLQuoteElement constructor is what would perform
the object allocation and it would pass along "q" as the localName.
(Though actually, HTMLQuoteElement is excitingly complicated, because
both <q> and <blockquote> would use that constructor, so it would need
to either require one of those two strings be passed in, or default to
"q" unless "blockquote" is passed in or something.)
The logical extension of this, then, is that if after that `document.registerElement` call I do
`document.body.innerHTML = <my-q cite="foo">blah</my-q>`
Ah, here we go. This is the part where the trouble starts, indeed.
This is why custom elements currently uses <q is="my-q"> for creating
custom element subclasses of things that are more specific than
HTMLElement. Yes, it's ugly. But the alternative is at least major
rewrite of the HTML spec and at least large parts of Gecko/WebKit/Blink.
:( I can't speak to whether Trident is doing a bunch of localName
checks internally.
However this idea that we'd like custom elements which inherit from existing
elements to have their internal slots ties in to the whole upgrading mess
Right, which you get for free with the <q is="my-q"> setup, since you
just get the slots for <q> and then the upgrade just has to worry about
your proto chain...
i.e. it might not be possible at all to make upgraded elements behave anything
like parsed-from-scratch elements.
I fully expect upgraded elements to perform worse than
parsed-from-scratch elements in practice, because of the deoptimizing
effects of the dynamic __proto__ mutation involved in the upgrade.
Maybe JS engines will work on making this deoptimize less, but it's not
clear to me that it's been a huge priority for them so far.
-Boris