Re: [webcomponents]: Platonic form of custom elements declarative syntax

Hi Allen,

Fortunately the state of this is pretty close to what you are suggesting.
We started of with the imperative solution and then went to look at a
declarative version. At this point, the discussion got a bit side tracked.
Lets back up and see what we have for the imperative version:

class MyElement extends HTMLElement {
  constructor() {
    ...
  }
  insertedCallback() {
    // now I'm in document
  }
  attributeChangedCallback(name, value) {
    // ...
  }
  doFunkyThing() {
    // ...
  }
}

// And tell the browser about this new shiny element
document.register('my-element, MyElement);

Fast forward...

For the declarative version we want to be able to associate a <template>
element to be used as the shadow dom for the custom element. We went around
in circles here and this thread was an attempt to start at a different
starting point to see where we would end up.

We initially had (plus/minus irrelevant details)

<element name="my-element">
  <template>
    This is my shadow DOM
    <content></content>
  </template>
  <script>
    class MyElement extends HTMLElement { ... }
    // We need a convenient way to register ('my-element, MyElement) here
  </script>
</element>

More inline...

On Thu, Apr 11, 2013 at 2:14 AM, Allen Wirfs-Brock <allen@wirfs-brock.com>wrote:

>
> On Apr 10, 2013, at 8:47 PM, Rick Waldron wrote:
>
> > cc Allen Wirfs-Brock, Dave Herman
> >
> > Allen, Dave
> >
> > Would you mind reading back through the  thread to provide some deeper
> insight? Thanks
> >
> > Rick
> >
>
> ECMAScript really has a very simply concept of 'this' out-side of a
> function.  It is a reference to the global object.  In all other cases
> 'this' occurs within a function body and is bound as part of a function
> innovation.  It would be a significant change to the ECMAScript semantics
> that are applied to 'this' the content of <script> tags.  I'm sure, it
> would only cause confusion.
>

Unfortunately NodeJS broke this invariant already. `this` inside a module
that has been required is a not the [[Global]] object. This has caused me a
lot of personal porting pain so I agree we must not break this invariant on
the web.


> I'm not at all up on the details and subtitles of what you are trying to
> do with your tempaltes, but regardless, I want to suggest an alternative
> approach that I'm pretty sure in the long run would be more natural for
> JavaScript programmers.
>
> It seems to me, what you are doing with templates is allowing user to
> define new kinds of DOM nodes and that when you "stamp out"  a template you
> are instantiating new instances of that kind of node.  In programming
> language terms, you are enabling markup authors to declarative define new
> "classes" of DOM nodes and to create instance of those classes.  The script
> behaviors you need to associate with a template are essentially the
> "methods" of the user defined classes.  Rather than twisting around the
> interpretation of 'this' in template script blocks and inventing other
> one-off extensions, it would be much better to recognize this class-based
> approach and just let the user define the class.
>
> Using ES6 syntax this could be very easy:
>
> <template bindtotagname="my_yay">
>     <shadowroot>
>         <div>Yay!</div>
>     </shadowroot>
>     <script>
>         class My_yay extends TemplatedNode {
>               constructor () {
>                      // runs when instances are created, can create per
> instance properties
>                      //  can be left out if nothing special is required
>                      }
>                whenBond(...args) {
>                       super(...args);   invoke default behavior inherited
> from TemplatedNode
>                       // my_yay specific behavior
>                       // in methods 'this' binds to an instance
>                      }
>                 anotherMethods() {  // other instance methods, properties
> of My_yay.prototype
>                      }
>                 static  anotherStaticMethods() { }  //properties of My_yay
>           }
>      </script>
> </template>
>
> Many details to work out, but I hope the intent is clear.  You just define
> a JS class corresponding to the template instances. There may be a standard
> template interface with methods such as withBond that are support.  Defaut
> implementations can be provided by a built-in super class.
>
> This can all be expresses, but less clearly and concisely using ES3/5
> syntax.  But since we are talking about a new HTML feature, I'd recommend
> being the first major HTMLfeature to embrace ES6 class syntax.  The class
> extension in ES6 are quite stable and quite easy to implement.  I'm pretty
> sure they will begin appearing in browsers sometime in the next 6 months.
> If webcomponents takes a dependency upon them, it would probably further
> speed up their implementation.
>

The problem here is how do you register `My_yay` as the class that goes
with the tag name `my_yay`. One option could be to use the completion value
but it seems too magical/unreliable. It also does not scale well. I would
like us to be able to put all custom component classes in a single js file:

<element name="my-foo">
  ...
</element>
<element name="my-bar">
  ...
</element>
<element name="my-baz">
  ...
</element>
<script src="my-elements.js></script>

// my-elements.js
someDocument.querySelector('[name=my-foo]').registerConstructor(MyFoo);
someDocument.querySelector('[name=my-bar]').registerConstructor(MyBar);
someDocument.querySelector('[name=my-baz]').registerConstructor(MyBaz);


This calls out for a less verbose and more DRY API.

-- 
erik

Received on Thursday, 11 April 2013 14:58:05 UTC