- From: Daniel Buchner <daniel@mozilla.com>
- Date: Wed, 6 Feb 2013 13:27:26 -0800
- 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>
- Message-ID: <CAHZ6zJHaugAu5Q9GgymBcudJh3RnraZoF+tEhF-UMvUyy=kwCw@mail.gmail.com>
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 UTC