Impending change: removal of dart:html's $dom_ members

195 views
Skip to first unread message

Pete Blois

unread,
Feb 19, 2013, 1:30:23 PM2/19/13
to mi...@dartlang.org
As part of our API cleanup process, we're planning on converting all of the DOM $dom_ APIs to be private.

These APIs have been available as lower-level alternatives to existing APIs, but their use has not been recommended.

Please let us know if you are using any of the $dom_ APIs and why, we'd like to fix those up before making this change.

Joao Pedrosa

unread,
Feb 19, 2013, 8:19:14 PM2/19/13
to mi...@dartlang.org
Hi,

I have been using these:

$dom_getComputedStyle
$dom_addEventListener
$dom_removeEventListener
$dom_getElementById
$dom_createElement

I think I got all of them.

At first I converted a JavaScript library of mine to Dart. So using those got me up and running in no time.

I liked $dom_getComputedStyle because the other one you scared me away from by demanding some Future stuff or something. Those APIs I used in a very synchronous way as they were being used from common functions being called indirectly. If I were to turn them into asynchronous calls, I have no idea what would happen. I know that recently you turned getComputedStyle into synchronous call so perhaps I can switch to it now.

The $dom_addEventListener and $dom_removeEventListener pair also lend themselves well to the legacy abstraction of calling JavaScript events and trying to deal with the differences of browsers on an ongoing basis. I'm more than happy to replace them with Dart abstractions if that would buy me something more.

I use $dom_getElementById quite a bit because I give elements generated IDs that are more easily found. I then keep the returned instance of Element stored for quicker turnaround.

$dom_createElement I use for creating all the elements based on information I collect via this class:

class TagConf {
  
  var tag, type, html, id, children, style, cls, value, size, rows, cols,
    wrap, href, name, src, width, height;
  
  TagConf({this.tag: 'div', this.type, this.html, this.id, this.children,
    this.style, this.cls, this.value, this.size, this.rows, this.cols,
    this.wrap, this.href, this.name, this.src, this.width, this.height});
  
  clone() {
    var a, c, cc = children;
    if (cc != null) {
      a = [];
      for (c in cc) {
        a.add(c.clone());
      }
    }
    return new TagConf(tag: tag, type: type, html: html, id: id,
      children: a, style: style, cls: cls, value: value, size: size,
      rows: rows, cols: cols, wrap: wrap, href: href, name: name, src: src,
      width: width, height: height);
  }

}

Overall what I wanted out of the APIs was synchronicity, performance and understandability so I knew what I got from them.

Cheers,
Joao

John Messerly

unread,
Feb 19, 2013, 8:41:02 PM2/19/13
to mi...@dartlang.org
On Tue, Feb 19, 2013 at 5:19 PM, Joao Pedrosa <joaop...@gmail.com> wrote:
I liked $dom_getComputedStyle because the other one you scared me away from by demanding some Future stuff or something. Those APIs I used in a very synchronous way as they were being used from common functions being called indirectly. If I were to turn them into asynchronous calls, I have no idea what would happen. I know that recently you turned getComputedStyle into synchronous call so perhaps I can switch to it now.

Agreed. I think getComputedStyle is synchronous now (as of last week's SDK?).
 
I use $dom_getElementById quite a bit because I give elements generated IDs that are more easily found. I then keep the returned instance of Element stored for quicker turnaround.

You should be able to use query('#elemId') for this.
 
$dom_createElement I use for creating all the elements based on information I collect via this class:

Joao Pedrosa

unread,
Feb 19, 2013, 10:44:08 PM2/19/13
to mi...@dartlang.org
Hi,

On Tue, Feb 19, 2013 at 10:41 PM, John Messerly <jmes...@google.com> wrote:
On Tue, Feb 19, 2013 at 5:19 PM, Joao Pedrosa <joaop...@gmail.com> wrote:
I liked $dom_getComputedStyle because the other one you scared me away from by demanding some Future stuff or something. Those APIs I used in a very synchronous way as they were being used from common functions being called indirectly. If I were to turn them into asynchronous calls, I have no idea what would happen. I know that recently you turned getComputedStyle into synchronous call so perhaps I can switch to it now.

Agreed. I think getComputedStyle is synchronous now (as of last week's SDK?).

I just tried it on my current SDK version and it seems to be the old way still. I'll have to wait some more to give the new API a try.
 
 
I use $dom_getElementById quite a bit because I give elements generated IDs that are more easily found. I then keep the returned instance of Element stored for quicker turnaround.

You should be able to use query('#elemId') for this.

Yup. As I store the IDs in a "DRId678" format, prepending it with "#" whenever I wanted to find an Element would be a little wasteful. I think many library authors would rather have a lookItUpById method alongside the more broad query one. I recall looking at the Ext.JS code once upon a time, and it too used a byId() method. I think libraries that work from generating Elements at runtime rather than HTML at development time do better with a byId() method.
 
$dom_createElement I use for creating all the elements based on information I collect via this class:

Would "new Element.tag" work here?

That picked up my interest indeed. Thanks for the heads up. I'll try to trim my uses of $dom_... methods preparing for the promised changes.

Cheers,
Joao

John Messerly

unread,
Feb 20, 2013, 6:20:31 PM2/20/13
to mi...@dartlang.org
On Tue, Feb 19, 2013 at 7:44 PM, Joao Pedrosa <joaop...@gmail.com> wrote:
On Tue, Feb 19, 2013 at 10:41 PM, John Messerly <jmes...@google.com> wrote:

You should be able to use query('#elemId') for this.

Yup. As I store the IDs in a "DRId678" format, prepending it with "#" whenever I wanted to find an Element would be a little wasteful. I think many library authors would rather have a lookItUpById method alongside the more broad query one. I recall looking at the Ext.JS code once upon a time, and it too used a byId() method. I think libraries that work from generating Elements at runtime rather than HTML at development time do better with a byId() method.

The theory of query("#$yourId") is that it should have same performance as getElementById. Any difference should be in the noise. If that isn't what you're seeing, do file a bug and we can add getElementById back without the $dom_ prefix.

Joao Pedrosa

unread,
Feb 21, 2013, 2:47:14 AM2/21/13
to mi...@dartlang.org
Hi,

I can live with the query("#$yourId") alternative. Thanks. I thought I used it more than I actually do. Most of my worries come from running more code during the startup, as the alternative of lazily loading code is a bit harder to engender. I'd also like to spend the time I could save on basic APIs on more complex APIs, that's why whenever a basic API makes things a bit more costly I worry a bit more myself. Dart has been packing up some abstractions that in JavaScript they don't need to pay ahead of time, and that's a source of worries for me. Then again, without Dart managing more code in JavaScript would be tougher, and that's the tradeoff that makes it worthwhile for me.

I've successfully removed all of the $dom_ dependencies but for the getComputedStyle one. I just noticed a new version of the editor/SDK is available so I'm going to give it a try and see whether I can remove that last dependency.

I found out about the new onMouseWheel event. On deltaY it returned 120 on WebKit and 3 on Gecko. Not exactly a full abstraction over the browser differences, but hopefully a little better than before.

I haven't been able to test on Internet Explorer since forever, but the new APIs will hopefully help with that too so I can remove more custom code.

In fact, by adopting the Dart abstractions I was able to remove a ton of custom code. Good thing that.

Cheers,
Joao

Pete Blois

unread,
Feb 22, 2013, 12:33:52 PM2/22/13
to mi...@dartlang.org
The WheelEvent API attempts to follow the W3C WheelEvent spec, which means that you need to check the deltaMode to see what units the scroll is in- pixels, or lines.

The change in behavior is that FF just started supporting the W3C events and Dart automatically started using that version when it became available.

One current issue is that the deltaY for FF appears to be inverted from the other browsers. Unfortunately the spec is unclear about the direction and FF is the only browser natively supporting the W3C wheel event. We'll fix this issue soon.


--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 

ducky

unread,
Jul 8, 2013, 6:32:43 AM7/8/13
to mi...@dartlang.org
Hi,
I am using $dom_createElementNS method of a document to create an element in a particular namespace in my document. I could not find another way of doing this in the existing API. 

I posted this question on SO and was recommended to post here:

Pete Blois

unread,
Jul 8, 2013, 11:55:52 AM7/8/13
to mi...@dartlang.org
Are there specific scenarios (namespaces) which this is needed for?


--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
 
 

Rohit Aggarwal

unread,
Jul 8, 2013, 1:43:25 PM7/8/13
to mi...@dartlang.org
I am using the svg namespace (http://www.w3.org/2000/svg) and the xlink namespace (http://www.w3.org/1999/xlink). For the first one, I could just use the SvgElement and get my work done. But I wanted to use what I already knew from JavaScript (https://developer.mozilla.org/en-US/docs/Web/API/document.createElementNS) and keep some things general.

If you were to remove this API, it may have impact in other places as well for the sake of consistency (I am not an expert) : getNamespacedAttributes of class Element. It seems to me to be inconsistent that you can't create a particular element in a namespace but you can set an attribute in a namespace.

Again, just to reiterate, I am a novice on namespaces and html. 

cheers


Simon Pai

unread,
Jul 9, 2013, 2:12:24 AM7/9/13
to mi...@dartlang.org
Hi Pete,

DQuery relies on Element.$dom_addEventListener(). If removed, the package is destroyed. So does Bootjack, which depends on DQuery.

Thanks,
Simon

Tom Yeh

unread,
Jul 9, 2013, 2:33:33 AM7/9/13
to mi...@dartlang.org
It is good to see the cleanup. However, some of methods shall be public since there are no good alternatives. Here is what we use in Rikulo UI.

1. $dom_addEventListener/$dom_removeEventListener: without them, it is not easy to listen an event that is known at run time (as a framework, we usually don't know which event at compile time). Of course, we can go over EventStreamProvider, but it is too heavy and stupid with such small feature. It will be great if you just rename them to addEventListener/removeEventListener.

2. UIEvent's $dom_charCode and $dom_keyCode. Reason: there are charCode and keyCode for KeyEvent and KeyboardEvent, but not UIEvent. This one is not critical but better to clarify.

3. Element's $dom_setAttribute. Is it the same as `attributes[key] = value`? If so, it is safe to remove it. (BTW, how about $dom_setAttributeNS? I didn't use it but I think it is  worth to explain how is the alternative)

Regards,
Tom


On Wednesday, February 20, 2013 2:30:23 AM UTC+8, Pete Blois wrote:

Florian Loitsch

unread,
Jul 9, 2013, 6:47:18 AM7/9/13
to General Dart Discussion
On Tue, Jul 9, 2013 at 8:33 AM, Tom Yeh <tom....@gmail.com> wrote:
It is good to see the cleanup. However, some of methods shall be public since there are no good alternatives. Here is what we use in Rikulo UI.

1. $dom_addEventListener/$dom_removeEventListener: without them, it is not easy to listen an event that is known at run time (as a framework, we usually don't know which event at compile time). Of course, we can go over EventStreamProvider, but it is too heavy and stupid with such small feature. It will be great if you just rename them to addEventListener/removeEventListener.
The EventStreamProvider looks like a very light-weight class. Did you run into any problems using it?
 

2. UIEvent's $dom_charCode and $dom_keyCode. Reason: there are charCode and keyCode for KeyEvent and KeyboardEvent, but not UIEvent. This one is not critical but better to clarify.

3. Element's $dom_setAttribute. Is it the same as `attributes[key] = value`? If so, it is safe to remove it. (BTW, how about $dom_setAttributeNS? I didn't use it but I think it is  worth to explain how is the alternative)

Regards,
Tom


On Wednesday, February 20, 2013 2:30:23 AM UTC+8, Pete Blois wrote:
As part of our API cleanup process, we're planning on converting all of the DOM $dom_ APIs to be private.

These APIs have been available as lower-level alternatives to existing APIs, but their use has not been recommended.

Please let us know if you are using any of the $dom_ APIs and why, we'd like to fix those up before making this change.

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new
 
 



--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett

Pete Blois

unread,
Jul 9, 2013, 6:08:44 PM7/9/13
to mi...@dartlang.org
Specifically for events, Element.on['random-event-name'] is an easy way to access arbitrary events. I will caution against using this for all events as we have polyfills for some events (specifically wheel and transition events) which will be skipped.

For namespaces and html, see:
Basically what's happening is that HTML5 is admitting that it's not XML and we're trying to minimize the legacy baggage around XML in DOM APIs that JS currently has. We currently do not support parsing arbitrary XML with Dart's DOM APIS (if it is supported it will most likely be in a dedicated XML parsing library which does not have all the browser quirks). In general though, I think that there are gaps in our APIs around namespaces- either in terms of not exposing enough or exposing too much.


On Tue, Jul 9, 2013 at 3:47 AM, Florian Loitsch <floi...@google.com> wrote:

On Tue, Jul 9, 2013 at 8:33 AM, Tom Yeh <tom....@gmail.com> wrote:
It is good to see the cleanup. However, some of methods shall be public since there are no good alternatives. Here is what we use in Rikulo UI.

1. $dom_addEventListener/$dom_removeEventListener: without them, it is not easy to listen an event that is known at run time (as a framework, we usually don't know which event at compile time). Of course, we can go over EventStreamProvider, but it is too heavy and stupid with such small feature. It will be great if you just rename them to addEventListener/removeEventListener.
The EventStreamProvider looks like a very light-weight class. Did you run into any problems using it?
 

2. UIEvent's $dom_charCode and $dom_keyCode. Reason: there are charCode and keyCode for KeyEvent and KeyboardEvent, but not UIEvent. This one is not critical but better to clarify.
According to the W3C spec, charCode and keyCode are not on UIEvent. These most likely do not work cross platform and I can't say for how long they will work on UIEvent.


3. Element's $dom_setAttribute. Is it the same as `attributes[key] = value`? If so, it is safe to remove it. (BTW, how about $dom_setAttributeNS? I didn't use it but I think it is  worth to explain how is the alternative)
It is the same, for non-namespaced attributes. 

Tom Yeh

unread,
Jul 9, 2013, 9:17:37 PM7/9/13
to mi...@dartlang.org

On Tue, Jul 9, 2013 at 8:33 AM, Tom Yeh <tom....@gmail.com> wrote:
It is good to see the cleanup. However, some of methods shall be public since there are no good alternatives. Here is what we use in Rikulo UI.

1. $dom_addEventListener/$dom_removeEventListener: without them, it is not easy to listen an event that is known at run time (as a framework, we usually don't know which event at compile time). Of course, we can go over EventStreamProvider, but it is too heavy and stupid with such small feature. It will be great if you just rename them to addEventListener/removeEventListener.
The EventStreamProvider looks like a very light-weight class. Did you run into any problems using it?

It and the `on` method brings in the Stream library which I don't think it is worth for a simple event listening. It is ok for sophisticated application since Future or other libraries will bring Stream in too. But, for a tiny application, the code size is everything.

Tom Yeh

unread,
Jul 9, 2013, 9:42:18 PM7/9/13
to mi...@dartlang.org
For example,

void main() {
  document.query("#id").$dom_addEventListener("click", (evt) {});
}

generates 28K bytes of JS code, while

void main() {
  document.query("#id").on["click"].listen((evt) {});
}

generates 75K bytes. (both minified)

It is a bit exaggerated since it is too small to be useful. But, I think it shows my concern.

Rohit Aggarwal

unread,
Jul 10, 2013, 6:46:48 AM7/10/13
to mi...@dartlang.org
Pete,
Thanks for the links on namespaces and html. They were pretty enlightening. I didn't realise that the html5 spec had removed most of them but not all (SVG and MathML). If thats the case, so be it. I'll remove that support from my work.

But I would suggest/recommend that there be still some generic ways to manipulate the three namespaces supported (xmlns, svg, mathml). For instance, I noticed without the namespace support, the only way to create an svg element is through dart:svg. That namespace API may sort of conflict with the design goal as mentioned in this doc under section: "More granular libraries".


cheers

Pete Blois

unread,
Jul 10, 2013, 11:15:15 AM7/10/13
to mi...@dartlang.org
The namespaces aren't quite gone, it's more like implicit namespaces during document parse. There seems to be a bit of a discrepancy in how namespaces are treated at parse time and how they are treated by the DOM APIs.
Reply all
Reply to author
Forward
0 new messages