Bug 20831 - [Custom]: Make document.register work with ES6 classes and @@create
Summary: [Custom]: Make document.register work with ES6 classes and @@create
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Component Model (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Dimitri Glazkov
QA Contact: public-webapps-bugzilla
Depends on:
Blocks: 17103
  Show dependency treegraph
Reported: 2013-01-31 00:00 UTC by Erik Arvidsson
Modified: 2013-04-22 22:45 UTC (History)
6 users (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Erik Arvidsson 2013-01-31 00:00:21 UTC

We need to make document.register work with ES6 classes and the ES6 @@create hook. For example:

class MyButton extends HTMLButton {
  constructor(text) {
    this.textContent = text;
document.register('my-button', {
  class: MyButton

Here is a rough draft/idea of how we need to modify the spec:

Modify the algorithm at https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register. This is a bit hand wavy and it ignores fallback on using "prototype".

1. If NAME is an invalid custom element name, throw an InvalidCharacterError exception.
2. If CLASS is not a Function throw TypeError.
3. Let PROTOTYPE be [[Get]](CLASS, "prototype").
4. If PROTOTYPE does not have Element.prototype on its prototype chain, throw a TypeError exception.
9?. Define CLASS.@create to be a function that creates a new element with the NAME as the tag name. TODO: Namespace from the prototype?
10. Return CLASS (for convenience?).

The create function in 9? is defined by https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-instantiation

I don't think we do not need the element finalization at all here since the constructor is itself the element finalization.

Since ES6 classes are just pure syntactic sugar for ES5 we should be able to the same thing for ES5. The new thing in ES6 is the @@create hook. For ES5 we could return an alternative function in step 10 that creates the instance object and then calls the user provided function.
Comment 1 Dimitri Glazkov 2013-02-07 21:32:33 UTC
There's also a nice long thread on public-webapps, where we ponder a slightly different syntax for ES5/3 to future-proof the API: http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/thread.html#msg250
Comment 2 Dimitri Glazkov 2013-02-12 18:03:26 UTC
From bug 20913, continuing discussion.

(In reply to comment #25)
> (In reply to comment #16)
> > It lets us to get rid of the creation callbacks, simplifies the spec, and
> > basically lets the builder of a component do exactly what they need at
> > creation time, instead of dealing with "created" and "shadowRootCreated".
> I'm sorry if I've somehow clouded the issue here, I don't oppose ES6 or
> extending DOM element objects via class/extends. I simply want the impact of
> changing doc.register to only take generated constructors to be clearly
> spelled out with a real example and realized. The above statement makes the
> current document.register property object sound like *it* is the complex,
> obtuse choice - what I'm saying is that it's the *opposite*. We're forcing
> constructors that have more cumbersome ergonomics and polyfill surface on
> folks that prefer not to use constructors for generating elements, as this
> survey shows:
> https://docs.google.com/forms/d/16cNqHRe-7CFRHRVcFo94U6tIYnohEpj7NZhY02ejiXQ/
> viewanalytics
> My contention is as follows: 
> Developers rarely use element constructors - there are several reasons,
> including: they're currently uncallable and throw (basically unusable,
> except for Image, Option, etc), devs have document.createElement and don't
> need them, they aren't programming Java.
> Why it matters:
> 1) We are arguing to change the interface to take only a parameter type that
> is largely irrelevant on the web today.
> 2) We lose easily defined callbacks to common actions - if we don't, *please
> correct me* and show an example. For instance, inside the constructor will I
> not be able to do: this.lifecycle.inserted = function(){...}? If so, yay, I
> am less concerned!

We're not losing callbacks. We are trying to get rid of construction callbacks only, because they are a hack around current platform limitations.

> 3) I am worried about boilerplate and monotony. Without answering the
> ergonomics questions about providing the functionality in the spec's current
> property object in a way easily accessible to developers within their
> user-generated constructor definitions, this concern persists.

I soothe your worry by promising to keep the non-construction callbacks :)
> document.register('super-list', {
>   prototype: Object.create(HTMLUListElement.prototype),
>   lifecycle: {
>     created: function(){
>       this.setAttribute('super', true);
>     },
>     inserted: function(){
>       // do something when super-list elements are added
>     }
>   }
> });
> Me thinks --> "Holy burgeoning boilerplate Batman!"

I hope to arrive to:

function SuperList() {
   this.setAttribute('super', true);
SuperList.prototype = Object.create(HTMLUListElement.prototype);
document.register('super-list', SuperList, {
   inserted: ...
Comment 3 Dimitri Glazkov 2013-02-20 18:48:32 UTC
Based on follow-up discussion, we are going to adopt two-pronged approach to the API: http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/thread.html#msg495
Comment 4 Dimitri Glazkov 2013-04-10 21:11:52 UTC
One more follow-up: by moving lifecycle callbacks to the prototype, we are able to skin the cat and eat it too. I may have mixed up my proverbs.

Comment 5 Dimitri Glazkov 2013-04-22 22:45:46 UTC
This is now awesome.