- From: Erik Arvidsson <arv@chromium.org>
- Date: Thu, 11 Apr 2013 10:57:16 -0400
- To: Allen Wirfs-Brock <allen@wirfs-brock.com>
- Cc: Rick Waldron <waldron.rick@gmail.com>, Daniel Buchner <daniel@mozilla.com>, John J Barton <johnjbarton@johnjbarton.com>, Dimitri Glazkov <dglazkov@google.com>, Scott Miles <sjmiles@google.com>, Rafael Weinstein <rafaelw@google.com>, public-webapps <public-webapps@w3.org>, Blake Kaplan <mrbkap@mozilla.com>, William Chen <wchen@mozilla.com>, Boris Zbarsky <bzbarsky@mozilla.com>, Jonas Sicking <jonas@sicking.cc>, Steve Orvell <sorvell@google.com>, Dave Herman <dherman@mozilla.com>
- Message-ID: <CAJ8+GogDbygd3PqTvgMUSN8xx6JtOZVXGLL0owo=0Zg9tH6eLQ@mail.gmail.com>
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