- 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