Re: A proposal for Element constructors

On Thu, Oct 27, 2011 at 1:34 AM, Kentaro Hara <haraken@chromium.org> wrote:

> Thanks, all!
>
> Adam:
> > Another solution to that "more than one tag per interface" problem is> to
> introduce subclasses of those interfaces for each tag.
> I agree. "new HTMLInsElement()" is more consistent with other Element
> constructors than "new HTMLModificationElement( {tagName: 'ins'} )".
>
>
> Rick:
> > As a developer that writes JavaScript every single day,
> > the sheer amount of typed characters required for using
> > the constructors in this proposal is enough for me to avoid it at all
> costs.
>
> I think that
>
>    new HTMLButtonElement( {disabled: true},
>                                                 [new Text("Click Me!!"),
>                                                  new Image( {src:
> "http://example.com/xxx.png"} ) ] );
>
> is as simple as you write it using Element.create(), and is much
> simpler and more readable than you write it using button.disabled and
> button.appendChild(). In any way, consistency with other DOM
> constructable objects and sub-typing are the advantages for letting
> Elements have constructors, as I described in the first mail.
>
>
No developer will ever opt-in to typing "HTMLButtonElement" over and over
again - the amount of shift-key holding alone is unacceptable.



>
> >> (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,
> ...)
>
> Alex Russell told me a better idea, just making the children array an
> optional "childNodes" or "children" property of the dictionary, like
> this:
>
>    new HTMLButtonElement( { disable: true, childNodes: [child1,
> child2, ...] } )
>
> We now do not need the second argument. I feel that just "a dictionary
> of Element properties" in the first argument is easy-to-understand.
>
>
>
> 2011年10月27日8:07 Rick Waldron <waldron.rick@gmail.com>:
> >
> > As a developer that writes JavaScript every single day, the sheer amount
> of typed characters required for using the constructors in this proposal is
> enough for me to avoid it at all costs.
> >
> >
> > On Tue, Oct 25, 2011 at 11: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)
> >
>
>
>
> --
> Kentaro Hara, Tokyo, Japan (http://haraken.info)
>

Received on Thursday, 27 October 2011 05:40:03 UTC