W3C home > Mailing lists > Public > public-webapps@w3.org > October to December 2011

Re: A proposal for Element constructors

From: Adam Barth <w3c@adambarth.com>
Date: Tue, 25 Oct 2011 20:54:29 -0700
Message-ID: <CAJE5ia9wDDYf_oOSPmkUm3-hiWD-2hm8rXdHx7er8j8L9AF_ag@mail.gmail.com>
To: Kentaro Hara <haraken@chromium.org>
Cc: public-webapps@w3.org, Dominic Cooney <dominicc@chromium.org>
Another solution to that "more than one tag per interface" problem is
to introduce subclasses of those interfaces for each tag.

Adam


On Tue, Oct 25, 2011 at 8:42 PM, Kentaro Hara <haraken@chromium.org> wrote:
> Hi folks,
> * Background *
> I have been working on making DOM objects look and feel more like ordinary
> JavaScript objects. I implemented Event constructors  [1], for example.
>
> * Proposal *
> Element.create() has proposed and been under discussion [2]. Besides
> Element.create(), I propose constructors for Elements, like "new
> HTMLButtonElement(...)", "new HTMLDivElement(...)" and "new
> HTMLVideoElement(...)". I think that both Element.create() *and* Element
> constructors are useful.
> For example,
>     var button = new HTMLButtonElement( {disabled: true},
>                                                                         [new
> TextNode("Click Me!!"),
>                                                                          new
> Image( {src: "http://example.com/xxx.png"} ) ] );
>     document.body.appendChild(button);
> is equivalent to the following HTML:
>     <button disabled>
>     Click Me!!
>     <img src = "http://example.com/xxx.png" />
>     </button>
> As shown in above, the constructor has two arguments. The first one is a
> dictionary of Element properties. The second one is an array of Nodes, which
> become child nodes of the Element.
>
> * Advantages of Element constructors *
> (a) Better errors when you misspell it
> Element.create("vdieo", {src: ...} ) ==> No error; HTMLUnknownElement is
> created
> new HTMLVdieoElement( {src: ...} ) ==> ReferenceError; Stack trace points
> you to the faulty line of code
> (b) Consistency with other constructable DOM objects
> e.g. new XMLHttpRequest(), new Image(), new Event(), new CustomEvent(), new
> MessageEvent(), ...
> (c) Enables to subtype DOM objects in the future
> We are planning to make DOM objects subtype-able, like this:
>     function MyButton(text) {
>         HTMLButtonElement.call(this);    /* (#) */
>         this.textContent = text;
>     }
>     MyButton.prototype = Object.create(HTMLButtonElement.prototype, {...});
>     var fancyButton = new MyButton("Click Me!!");
> In order to make the line (#) work, HTMLButtonElement must have a
> constructor.
>
> * Spec examples *
> interface [
>     NamedConstructor(optional HTMLButtonElementInit initDict, optional
> NodeArray children)
> ] HTMLButtonElement : HTMLElement {
>     attribute boolean disabled;
>     attribute DOMString value;
>     ... (omitted)
> }
> dictionary HTMLButtonElementInit : HTMLElementInit {
>     boolean disabled;
>     DOMString value;
>     ... (omitted)
> }
> interface [
>     NamedConstructor(optional HTMLElementInit initDict, optional NodeArray
> children)
> ] HTMLElement : Element {
>     attribute DOMString lang;
>     attribute DOMString className;
>     ... (omitted)
> }
> dictionary HTMLElementInit : ElementInit {
>     DOMString lang;
>     DOMString className;
>     ... (omitted)
> }
> interface Element : Node {
>     readonly attribute DOMString tagName;
>     ... (omitted)
> }
> dictionary ElementInit : NodeInit {
>     DOMString tagName;
>     ... (omitted)
> }
> interface Node {
>     readonly attribute unsigned short nodeType;
>     ... (omitted)
> }
> dictionary NodeInit {
>     unsigned short nodeType;
>     ... (omitted)
> }
>
> * Discussion
> (a) Element.create() *and* Element constructors?
> I think that both are useful for the reasons that dominicc pointed out in
> [3]. Element.create() is good when we have a tag name in hand, like
>     var tag = "button";
>     Element.create(tag, { }, ...);
> On the other hand, Element constructors have the advantages that I described
> above.
> (b) How to specify properties and attributes in the dictionary argument
> A property and an attribute are two different things [4]. A property is the
> thing that can be set by a setter like foo.value, and an attribute is the
> thing that can be set by foo.setAttribute(). A discussion has been conducted
> on how we can set up properties and attributes in the dictionary argument
> [2]. Proposed approaches in [2] are as follows:
> (b-1) Let a constructor have two dictionaries, one for properties and the
> other for attributes, e.g. new HTMLButtonElement( {disabled: true}, {class:
> "myButton", onclick: func}, ...)
> (b-2) Add a prefix character to attributes, e.g new HTMLButtonElement(
> {disabled: true, "@class": "myButton", "@onclick": func} )
> (b-3) Introduce a reserved key "attributes", e.g new HTMLButtonElement(
> {disabled: true, attributes: {class: "myButton", onclick: func} } )
> Another difficulty around attributes is how to naturally set a value of a
> boolean attribute in the dictionary when we have the value in hand. In case
> of a property, you just need to write like this:
>     var b = new HTMLButtonElement({disabled: value});
> However, in case of an attribute, we need to write like this:
>     var options = {};
>     if (value)
>         options.disabled = "";
>     var b = new HTMLButtonElement(options);
> Basically, I think that we should keep the succinctness of constructors and
> should not introduce a new syntax just for allowing people to set attributes
> in the constructor. Thus, I propose that we allow only properties in the
> dictionary, at least at the present moment. If we found in the future that
> people wish to set attributes in the constructor, we can discuss the feature
> again then.
> (c) How to specify child Elements in the constructor argument
> Possible approaches are as follows:
> (c-1) As variable arguments, e.g. new HTMLButtonElement( { ... }, child1,
> child2, child3, ...)
> (c-2) As an array, e.g. new HTMLButtonElement( { ... }, [child1, child2,
> child3] )
> (c-3) As variable arguments. We expand arguments of type array. e.g. new
> HTMLButtonElement( { ... }, child1, [child2, child3], child4, ...) is
> equivalent to new HTMLButtonElement({ ... }, child1, child2, child3, child4,
> ...)
> I guess that (c-3) is not good for the complicated rule. I think that both
> (c-1) and (c-2) are possible, but I prefer (c-1). I think that implicit
> array expansion is not necessary, since ES6 is introducing "..." operator
> for array expansion [6]. In other words, you can write like this:
>     var array = [child1, child2, child3, ......];
>     new HTMLButtonElement({ ...... }, ...array);
> (d) What should the owner document of the created Element be?
> I think that we can assume that the owner document is window.document, as
> existing constructors (new Image(), new Audio() and new Option()) is
> assuming. Some cases can expect an owner document other than
> window.document, but they are not so common. I believe that we should focus
> on making most of practical use cases simpler rather than supporting
> specialized cases that do not really need a convenience shortcut.
> (e) How to specify a namespace of attributes
> I propose that we do not support namespaced attributes like "xmlns:foo",
> since they are rare [5]. Again, we should focus on making most of practical
> use cases simpler.
> (f) How to create an unknown element that can be created by
> document.createElement("unknooooown")
> Fortunately, the HTML5 spec has HTMLUnknownElement. You can create an
> unknown element by new HTMLUnknownElement( {tagName: "unknooooown"}, ...)
> (g) How to handle HTMLElements that have more than one tags
> For example, both <ins> and <del> are tags of HTMLModificationElement. Then,
> how does the constructor look like? I think that we can easily handle this
> issue by distinguishing tags using a tagName property, e.g. new
> HTMLModificationElement( {tagName: "ins"}, ...) or new
> HTMLModificationElement( {tagName: "del"}, ...)
>
> [1] https://bugs.webkit.org/show_bug.cgi?id=67824
> [2] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0537.html
> [3] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0707.html
> [4] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0666.html
> [5] http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/0721.html
> [6] http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts (11.2.4
> Argument Lists)
>
>
> --
> Kentaro Hara, Tokyo, Japan (http://haraken.info)
>
Received on Wednesday, 26 October 2011 03:55:29 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 18:49:48 GMT