Re: ES6 and upgrading custom elements
On Wed, Jan 7, 2015 at 5:53 AM, Domenic Denicola d...@domenic.me wrote: ... all instances of MyInputElement will get all internal slots and other exotic behavior of HTMLInputElement. That's why I tried to scope this thread to upgrading and not the script side. The main question is how you tie MyInputElement to something like my-input and have that actually work. It seems Dimitri's answer is that you don't, you use input is=my-input in combination with a (delayed) prototype mutation and creation callback. And you use createElement(input, my-input) or the constructor on the script side of things. Which is that the HTML standard should just define that `HTMLInputElement.extends = input`. We could have that I guess, but it still doesn't help with upgrading, does it? -- https://annevankesteren.nl/
RE: ES6 and upgrading custom elements
From: annevankeste...@gmail.com [mailto:annevankeste...@gmail.com] On Behalf Of Anne van Kesteren That's why I tried to scope this thread to upgrading and not the script side. The main question is how you tie MyInputElement to something like my-input and have that actually work. It seems Dimitri's answer is that you don't, you use input is=my-input in combination with a (delayed) prototype mutation and creation callback. And you use createElement(input, my-input) or the constructor on the script side of things. Oh my goodness, I'm sorry. I completely misunderstood what was meant by upgrading. My fault entirely, as it's a well-defined custom elements term. I see the problem now. I'll try to think on it harder and get back to you. In the meantime, apologies for derailing the thread.
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 10:38 AM, Anne van Kesteren ann...@annevk.nl wrote: On Tue, Jan 6, 2015 at 7:06 PM, Dimitri Glazkov dglaz...@google.com wrote: Yes to the first question. I wasn't planning on doing anything different there. It seems simple prototype munging but not actually changing identity will fail for all but the basic cases of subclassing. E.g. if I subclass an HTMLInputElement I would expect it to have an internal [[value]] slot of sorts, but since the element created is a plain HTMLElement whose prototype is munged that will not be the case. Right, that's why to create a valid custom element that subclasses HTMLInputElement, you should use type extensions. With type extensions, the HTMLInputElement is what's instantiated. :DG
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 10:59 AM, Anne van Kesteren ann...@annevk.nl wrote: On Tue, Jan 6, 2015 at 7:54 PM, Dimitri Glazkov dglaz...@google.com wrote: Right, that's why to create a valid custom element that subclasses HTMLInputElement, you should use type extensions. With type extensions, the HTMLInputElement is what's instantiated. But without using type extensions this will work (provided we sort out the other bits): class X extends HTMLInputElement { ... } document.registerElement(x-input, X) var xinput = new X It seems sad to require type extensions (and therefore requiring a more complicated version of document.registerElement) for translating this into markup. You shouldn't need anything more complicated: class X extends HTMLInputElements { .. } X.extends = input // additional line. document.register(x-input, X) var xinput = new X Having actual subclassing in JavaScript, but not for elements unless you use some sort of hack seems sad. The type extensions is a hack, I agree :( :DG
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 7:54 PM, Dimitri Glazkov dglaz...@google.com wrote: Right, that's why to create a valid custom element that subclasses HTMLInputElement, you should use type extensions. With type extensions, the HTMLInputElement is what's instantiated. But without using type extensions this will work (provided we sort out the other bits): class X extends HTMLInputElement { ... } document.registerElement(x-input, X) var xinput = new X It seems sad to require type extensions (and therefore requiring a more complicated version of document.registerElement) for translating this into markup. Having actual subclassing in JavaScript, but not for elements unless you use some sort of hack seems sad. -- https://annevankesteren.nl/
RE: ES6 and upgrading custom elements
This is all intimately tied to the still-ongoing how-to-subclass-builtins discussion that is unfortunately happening on a private TC39 thread. The essential idea, however, is that as long as you do ```js class MyInputElement extends HTMLInputElement { constructor() { super(); // this is key } } ``` then all instances of MyInputElement will get all internal slots and other exotic behavior of HTMLInputElement. The `super()` call is the signal that the object should be allocated and initialized using the logic of HTMLInputElement instead of Function.prototype (the default). This will require defining a constructor for HTMLInputElement, of course, but it's pretty predictable you wouldn't be able to create subclasses of something without a constructor. I am not sure exactly how this fits in with an ES6-era document.registerElement. This is the right time to start thinking about that, certainly. Off the top of my head, ideally document.registerElement should just be a registration call, and should not actually need to modify the constructor or create a new constructor as it does today. The generated constructor in [1] does nothing special that the above constructor (which consists entirely of `super()`) could not be made to do automatically, as long as the Element constructor was made smart enough. (`super()` eventually will delegate up to the Element constructor.) To explain that in more detail I need one more probable-ES6 concept, which is the new target. In the expression `var x = new MyInputElement()`, ` MyInputElement` is the new target. Part of the ES6 subclassing story is that all superclass constructors will be passed an implicit parameter for the new target. So, when the `MyInputElement()` constructor calls `super()`, that calls the [[Construct]] internal method of HTMLInputElement, passing in the new target of MyInputElement. Similarly when HTMLInputElement in turn calls `super()`, that will call the [[Construct]] internal method of HTMLElement, still passing in the new target of MyInputElement. Etc. until Element also gets a new target of MyInputElement. With this in hand we could see how to define a smart enough element constructor. It would first look up the new target in the custom element registry. If it is there, it retrieves the definition for it, and can do all the work currently specified in [1]. That means that the actual constructor for `MyInputElement` can be as above, i.e. simply `super()`. [1]: https://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-constructor-generation Conceptually, when I wrote it I'd imagined that the constructor will be called only when you explicitly invoke it (new FooElement...). When parsing or upgrading, the constructor would not be called. The createdCallback will be invoked in either case. I do not think this makes any sense. All instances of a class can only be created through its constructor. createdCallback should be left behind as legacy IMO. -- With all this in mind I do not think extends is necessary. I am less sure about this though so take what follows with a grain of salt. But anyway, IMO you should just look at the inheritance chain for the constructor passed in to registerElement. Also there is a pretty simple hack if you still want extends. Which is that the HTML standard should just define that `HTMLInputElement.extends = input`. Then in Dmitry's ```js class X extends HTMLInputElement { .. } X.extends = input // additional line. document.register(x-input, X) var xinput = new X ``` the need for the additional line disappears since `X.extends === HTMLInputElement.extends === input`. (I guess this breaks for classes that have multiple tag names :-/. But it is pretty weird that I can't define `class QQ extends HTMLQuoteElement {}` and then do both `q is=x-qq` and `blockquote is=x-qq`. You would think I could do both. More reason to dislike `extends`.)
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 6:13 PM, Dimitri Glazkov dglaz...@google.com wrote: That section needs to be updated, because the ES6 spec had shifted a little bit with regard to @@create. Filed https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769. Yeah, there's issues in general there, such as ES6 giving up on explaining all of DOM :-( Conceptually, when I wrote it I'd imagined that the constructor will be called only when you explicitly invoke it (new FooElement...). When parsing or upgrading, the constructor would not be called. The createdCallback will be invoked in either case. Would you do the prototype munging that is specified in createdCallback today? (I think it would be more clear if we made that prototype munging part of the upgrade algorithm by the way.) How else would that work? Pass a reference to the old element and let the developer handle it? -- https://annevankesteren.nl/
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 9:56 AM, Anne van Kesteren ann...@annevk.nl wrote: On Tue, Jan 6, 2015 at 6:13 PM, Dimitri Glazkov dglaz...@google.com wrote: That section needs to be updated, because the ES6 spec had shifted a little bit with regard to @@create. Filed https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769. Yeah, there's issues in general there, such as ES6 giving up on explaining all of DOM :-( Conceptually, when I wrote it I'd imagined that the constructor will be called only when you explicitly invoke it (new FooElement...). When parsing or upgrading, the constructor would not be called. The createdCallback will be invoked in either case. Would you do the prototype munging that is specified in createdCallback today? (I think it would be more clear if we made that prototype munging part of the upgrade algorithm by the way.) How else would that work? Pass a reference to the old element and let the developer handle it? Yes to the first question. I wasn't planning on doing anything different there. And yes, I would like to fix the munging clarity as part of https://www.w3.org/Bugs/Public/show_bug.cgi?id=27437. :DG -- https://annevankesteren.nl/
Re: ES6 and upgrading custom elements
That section needs to be updated, because the ES6 spec had shifted a little bit with regard to @@create. Filed https://www.w3.org/Bugs/Public/show_bug.cgi?id=27769. Conceptually, when I wrote it I'd imagined that the constructor will be called only when you explicitly invoke it (new FooElement...). When parsing or upgrading, the constructor would not be called. The createdCallback will be invoked in either case. :DG On Tue, Jan 6, 2015 at 7:21 AM, Anne van Kesteren ann...@annevk.nl wrote: It's not clear to me from https://w3c.github.io/webcomponents/spec/custom/#es6 how the upgrade works. From the pre-ES6 setup you can work out through inference that upgrading is supposed to mutate the prototype of the element in question. But it seems that mutating the prototype is not sufficient for ES6. We want an element created through the constructor, no? (Let's leave aside the question for now as to how this subclassing would work, that's already discussed elsewhere.) -- https://annevankesteren.nl/
Re: ES6 and upgrading custom elements
On Tue, Jan 6, 2015 at 7:06 PM, Dimitri Glazkov dglaz...@google.com wrote: Yes to the first question. I wasn't planning on doing anything different there. It seems simple prototype munging but not actually changing identity will fail for all but the basic cases of subclassing. E.g. if I subclass an HTMLInputElement I would expect it to have an internal [[value]] slot of sorts, but since the element created is a plain HTMLElement whose prototype is munged that will not be the case. -- https://annevankesteren.nl/