W3C home > Mailing lists > Public > public-webapps@w3.org > January to March 2013

Re: document.register and ES6

From: Daniel Buchner <daniel@mozilla.com>
Date: Wed, 6 Feb 2013 13:27:26 -0800
Message-ID: <CAHZ6zJHaugAu5Q9GgymBcudJh3RnraZoF+tEhF-UMvUyy=kwCw@mail.gmail.com>
To: Scott Miles <sjmiles@google.com>
Cc: Erik Arvidsson <arv@chromium.org>, Dimitri Glazkov <dglazkov@google.com>, public-webapps <public-webapps@w3.org>, Boris Zbarsky <bzbarsky@mit.edu>
So you're directly setting the user-added methods on matched elements in
browsers that don't support proto, but what about accessors?

If we modified the spec (as previously suggested) to take an *unbaked*
prototype object, we could polyfill all property types:

var myButton = document.register('x-mybutton', {
    prototype: {
        foo: {
            set: function(){ ... },
            get: function(){ ... }
        }
    }
});

Equipped with the unbaked prototype descriptor, in your upgrade phase, you
should be able to simply bake the node with:
Object.defineProperties(element, unbakedPrototypeDescriptor) - right?

Daniel J. Buchner
Product Manager, Developer Ecosystem
Mozilla Corporation


On Wed, Feb 6, 2013 at 1:07 PM, Scott Miles <sjmiles@google.com> wrote:

> Well, this (non-robust quicky test) works in IE:
>
> http://jsfiddle.net/zUzCx/1/
>
>
> On Wed, Feb 6, 2013 at 12:59 PM, Scott Miles <sjmiles@google.com> wrote:
>
>> Afaik, the 'generated constructor' is technical debt we are stuck with
>> until we can actually invoke DOM constructors from JS. If there is a better
>> way around it, I'm all ears!
>>
>> polyfilling without __proto__: I don't know if it's possible, which is a
>> good point. I was basically ignoring that problem, but I guess I should not
>> do that: we may have to utterly change our target.
>>
>> Iow, perhaps we can decorate node instances with API scraped off of a
>> separate prototype chain. Ironically, this is close to what my component
>> sugaring layer does anyway, in order to support protected API.
>>
>> S
>>
>>
>> On Wed, Feb 6, 2013 at 12:50 PM, Erik Arvidsson <arv@chromium.org> wrote:
>>
>>> If we are willing to return a new constructor function I think we have
>>> no problems. I was concerned that it would lead to people using the
>>> wrong function but it does solve the issues.
>>>
>>> class MyButtonImpl extends HTMLButtonElement {
>>> }
>>> let MyButton = document.register('my-button', {
>>>   class: MyButtonImpl // maybe call the property "implementation" if
>>> we don't want to use "class".
>>> });
>>>
>>> I feel like this is getting close to my pain tolerance for boilerplate
>>> code but I'm willing to realize that currently this is the only
>>> working proposal (for polyfilling in __proto__ browser).
>>>
>>> I'm still curious how people are planning to do this in non __proto__
>>> browsers?
>>>
>>> On Wed, Feb 6, 2013 at 3:43 PM, Scott Miles <sjmiles@google.com> wrote:
>>> > Yes, it's not intended to work in IE ... I used __proto__.
>>> >
>>> >
>>> > On Wed, Feb 6, 2013 at 12:41 PM, Daniel Buchner <daniel@mozilla.com>
>>> wrote:
>>> >>
>>> >> Scott: is this example not intended to work in IE9? It throws, the
>>> output
>>> >> object is missing the 'oranginate' method.
>>> >>
>>> >> Daniel J. Buchner
>>> >> Product Manager, Developer Ecosystem
>>> >> Mozilla Corporation
>>> >>
>>> >>
>>> >> On Wed, Feb 6, 2013 at 12:32 PM, Scott Miles <sjmiles@google.com>
>>> wrote:
>>> >>>
>>> >>> There were several errors in my pseudo-code, here is a working
>>> version:
>>> >>>
>>> >>> http://jsfiddle.net/yNbnL/1/
>>> >>>
>>> >>> S
>>> >>>
>>> >>>
>>> >>> On Wed, Feb 6, 2013 at 12:01 PM, Scott Miles <sjmiles@google.com>
>>> wrote:
>>> >>>>
>>> >>>> Errata:
>>> >>>>  makePrototypeTwiddlingConstructorForDomNodes needs to know the
>>> extendee
>>> >>>>
>>> >>>> var ctor = makePrototypeTwiddlingConstructorForDomNodes(inExtends,
>>> >>>> inClass);
>>> >>>>
>>> >>>>
>>> >>>> On Wed, Feb 6, 2013 at 11:59 AM, Scott Miles <sjmiles@google.com>
>>> wrote:
>>> >>>>>
>>> >>>>> On Wed, Feb 6, 2013 at 11:18 AM, Erik Arvidsson <arv@chromium.org>
>>> >>>>> wrote:
>>> >>>>>>
>>> >>>>>> On Wed, Feb 6, 2013 at 1:38 PM, Scott Miles <sjmiles@google.com>
>>> >>>>>> wrote:
>>> >>>>>> > Sorry, replace MyButton.super() with MyButton.super.call(this);
>>> >>>>>> >
>>> >>>>>> >
>>> >>>>>> > On Wed, Feb 6, 2013 at 10:37 AM, Scott Miles <
>>> sjmiles@google.com>
>>> >>>>>> > wrote:
>>> >>>>>> >>
>>> >>>>>> >> So, neglecting issues around the syntax of document.register
>>> and
>>> >>>>>> >> the
>>> >>>>>> >> privatization of callbacks, is it fair to say the following is
>>> the
>>> >>>>>> >> intended
>>> >>>>>> >> future:
>>> >>>>>> >>
>>> >>>>>> >> class MyButton extends HTMLButtonElement {
>>> >>>>>> >>   constructor() {
>>> >>>>>> >>     super();
>>> >>>>>> >>     // make root, etc.
>>> >>>>>> >>   }
>>> >>>>>> >> }
>>> >>>>>> >> document.register('x-button', MyButton);
>>> >>>>>> >>
>>> >>>>>> >> If so then can we do this in the present:
>>> >>>>>> >>
>>> >>>>>> >> MyButtonImpl = function() {
>>> >>>>>>
>>> >>>>>> What do you mean here?
>>> >>>>>>
>>> >>>>>> >>   MyButton.super();
>>> >>>>>>
>>> >>>>>> Did you get that backwards? I don't see how MyButtonImpl can be
>>> >>>>>> derived from MyButton.
>>> >>>>>
>>> >>>>>
>>> >>>>> Its not. The 'super' means 'the super-class constructor for
>>> MyButton
>>> >>>>> that does not include magic DOM object generation' (in this case,
>>> >>>>> HTMLButtonElement). For MyDerivedButton, MyDerivedButton.super
>>> would point
>>> >>>>> to MyButtonImpl.
>>> >>>>>
>>> >>>>> The existence of MyButtonImpl is an unfortunate side-effect of
>>> needing
>>> >>>>> a generated constructor.
>>> >>>>>
>>> >>>>> The idea is to correspond as closely as possible with the ES6
>>> version.
>>> >>>>> MyButtonImpl goes away in ES6, it's purpose in the meantime is
>>> just to
>>> >>>>> provide something that looks like a proper class.
>>> >>>>>
>>> >>>>> I could write it this way:
>>> >>>>>
>>> >>>>> MyButton = function() {
>>> >>>>>
>>> >>>>>  MyButton.super();
>>> >>>>>  // make root, etc.
>>> >>>>> };
>>> >>>>> MyButton.prototype = Object.create(HTMLButtonElement, { ... });
>>> >>>>> MyButton = document.register(‘x-button’, MyButton);
>>> >>>>>
>>> >>>>> Written this way, MyButton no longer refers to the constructor you
>>> >>>>> specified, but instead refers to the generated constructor. This is
>>> >>>>> conceptually cleaner, but it's a bit tricky. For maximum clarity,
>>> I named
>>> >>>>> the internal version MyButtonImpl in my example code, but there is
>>> no reason
>>> >>>>> to have that symbol.
>>> >>>>>
>>> >>>>>>
>>> >>>>>>
>>> >>>>>> >>   // make root, etc.
>>> >>>>>> >> };
>>> >>>>>> >> MyButtonImpl.prototype = Object.create(HTMLButtonElement, {
>>> ... });
>>> >>>>>> >>
>>> >>>>>> >> // the ‘real’ constructor comes from document.register
>>> >>>>>> >> // register injects ‘super’ into MyButton
>>> >>>>>> >> MyButton = document.register(‘x-button’, MyButtonImpl);
>>> >>>>>>
>>> >>>>>> What is the relationship between MyButton and MyButtonImpl?
>>> >>>>>>
>>> >>>>>> If MyButton.__proto__ === MyButtonImpl and
>>> >>>>>> MyButton.prototype.__proto__ === MyButtonImpl.prototype then this
>>> >>>>>> might work (but this cannot be polyfilled either).
>>> >>>>>>
>>> >>>>>
>>> >>>>> MyButton.prototype == MyButtonImpl.prototype or
>>> >>>>> MyButton.prototype.__proto__ == MyButtonImpl.prototype, depending
>>> on needs.
>>> >>>>>
>>> >>>>> MyButton itself does magic DOM construction work that we cannot do
>>> with
>>> >>>>> normal inheritance, then invokes MyButtonImpl. MyButtonImpl is
>>> never used as
>>> >>>>> a constructor itself (not as an argument to 'new' anyway).
>>> >>>>>
>>> >>>>> From the user's perspective, he has made a single class which
>>> >>>>> implements his element (the goal!). The unfortunate name
>>> shenanigan (I
>>> >>>>> called my class MyButtonImpl, but after 'register' I refer to it as
>>> >>>>> MyButton) is the simplest way I could conceive to overcome the
>>> 'generated
>>> >>>>> constructor' problem.
>>> >>>>>
>>> >>>>> To be clear, everything I come up with is intended to polyfill
>>> (modulo
>>> >>>>> my error), because I generally am writing those myself (at first
>>> anyway).
>>> >>>>> One version might look like this:
>>> >>>>>
>>> >>>>> document.register = function(inExtends, inClass) {
>>> >>>>>   var ctor = makePrototypeTwiddlingConstructorForDomNodes(inClass);
>>> >>>>>   ctor.prototype = inClass.prototype;
>>> >>>>>   addToTagRegistry(inExtends, ctor, inClass);
>>> >>>>>   ctor.super = getClassForExtendee(inExtends);
>>> >>>>>   return ctor;
>>> >>>>> };
>>> >>>>>
>>> >>>>>
>>> >>>>>> --
>>> >>>>>> erik
>>> >>>>>
>>> >>>>>
>>> >>>>
>>> >>>
>>> >>
>>> >
>>>
>>>
>>>
>>> --
>>> erik
>>>
>>
>>
>
Received on Wednesday, 6 February 2013 21:28:25 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 18:49:57 GMT