Batik doesn't allow adding JavaScript properties to node objects

View: New views
11 Messages — Rating Filter:   Alert me  

Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello all,

would you consider this a bug in Batik 1.7?  The code below works in Firefox, Opera, IE+ASV and Safari, but Squiggle complains "ReferenceError: "saveClick" is not defined. (Event attribute file:/E:/programmieren/svg/js/js_attribute_to_node_object.svg:16 onclick#1)".  


<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <script type="text/javascript"><![CDATA[
    saveClick = function(evt) {
      evt.target.lastClick = evt
      alert("Click position is " +
            evt.target.lastClick.clientX + "," +
            evt.target.lastClick.clientY)
    }

  ]]></script>

  <rect width="100" height="100" x="150" y="150" onclick="saveClick(evt)"/>
</svg>


I guess Batik's node objects are in fact Java object that can't simply be given new properties (though the error message doesn't really suggest this).

I find that being able to store JavaScript properties directly inside node objects can be very handy.  An alternative would be a table that associates the node objects with other objects that in turn store the properties.  That's however not as neat!

Thomas W.


Re: Batik doesn't allow adding JavaScript properties to node objects

by Cameron McCormack-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Thomas.

th_w@...:
> would you consider this a bug in Batik 1.7? The code below works
> in Firefox, Opera, IE+ASV and Safari, but Squiggle complains
> "ReferenceError: "saveClick" is not defined. (Event attribute
> file:/E:/programmieren/svg/js/js_attribute_to_node_object.svg:16
> onclick#1)".

There was a bug fixed (after the 1.7 release I believe) where scripts
identified by different media types that in reality are just different
names for JavaScript were being executed in different environments.  In
your case it might be because the default language for event attributes
clike onclick="" is text/ecmascript, while the <script> element is using
text/javascript.

Try removing the type="text/javascript" from the <script> element.

This bug should be fixed in nightly builds, btw.

--
Cameron McCormack ≝ http://mcc.id.au/

Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Cameron,

thanks for your reply.

--- In svg-developers@..., Cameron McCormack <cam@...> wrote:

>
> th_w@...:
> > would you consider this a bug in Batik 1.7? The code below works
> > in Firefox, Opera, IE+ASV and Safari, but Squiggle complains
> > "ReferenceError: "saveClick" is not defined. (Event attribute
> > file:/E:/programmieren/svg/js/js_attribute_to_node_object.svg:16
> > onclick#1)".
>
> There was a bug fixed (after the 1.7 release I believe) where scripts
> identified by different media types that in reality are just different
> names for JavaScript were being executed in different environments.  In
> your case it might be because the default language for event attributes
> clike onclick="" is text/ecmascript, while the <script> element is using
> text/javascript.
>
> Try removing the type="text/javascript" from the <script> element.
>


Unfortunately that doesn't change anything.  I changed the code to add the event dynamically.  Now there is no error message any more, but Squiggle silently fails to store the click in the node object, while Firefox, Opera, IE + ASV and Safari work as expected:


<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" onload="init()">
  <script><![CDATA[
  init = function() {
      var rect = document.getElementById("myrect")
      alert("rect: " + rect)
      rect.addEventListener("click",function(evt) {
          alert("lastClick: " + evt.target.lastClick)
          evt.target.lastClick = evt
          alert("Click stored")
        },false
      )
    }
  ]]></script>

  <rect id="myrect" width="100" height="100" x="150" y="150"/>
</svg>


> This bug should be fixed in nightly builds, btw.
>


I downloaded a more recent build from here:
http://mcc.id.au/batik-nightly/batik-nightly-2009-08-06.zip

I still get the same results.  Are there more up to date nightly builds anywhere?  I'm not too keen on building Batik myself from the SVN because I'm not (yet ;-)) so Java savvy, and all the classpath stuff is still frightening to me.

Thomas W.


Re: Re: Batik doesn't allow adding JavaScript properties to node objects

by Cameron McCormack-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Thomas.

th_w@...:

> Unfortunately that doesn't change anything. I changed the code to add
> the event dynamically. Now there is no error message any more, but
> Squiggle silently fails to store the click in the node object, while
> Firefox, Opera, IE + ASV and Safari work as expected:
>
> <?xml version="1.0"?>
> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
>   "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
>
> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" onload="init()">
>   <script><![CDATA[
>   init = function() {
>       var rect = document.getElementById("myrect")
>       alert("rect: " + rect)
>       rect.addEventListener("click",function(evt) {
>           alert("lastClick: " + evt.target.lastClick)
>           evt.target.lastClick = evt
>           alert("Click stored")
>         },false
>       )
>     }
>   ]]></script>
>
>   <rect id="myrect" width="100" height="100" x="150" y="150"/>
> </svg>

Ah, Batik doesn’t support “expando” properties on host objects like
Nodes.  So assigning to .lastClick is throwing an exception.

If you want to store some custom information on the <rect> element, you
can use the DOM 3 Core setUserData() method:

  alert("lastClick: " + evt.target.getUserData("lastClick"));
  evt.target.setUserData("lastClick", evt, null);
  alert("Click stored");

> > This bug should be fixed in nightly builds, btw.
>
> I downloaded a more recent build from here:
> http://mcc.id.au/batik-nightly/batik-nightly-2009-08-06.zip
>
> I still get the same results. Are there more up to date nightly builds
> anywhere? I'm not too keen on building Batik myself from the SVN
> because I'm not (yet ;-)) so Java savvy, and all the classpath stuff
> is still frightening to me.

That’s the most up-to-date build.

--
Cameron McCormack ≝ http://mcc.id.au/

Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

--- In svg-developers@..., Cameron McCormack <cam@...> wrote:

>
> Hi Thomas.
>
> th_w@...:
> > Unfortunately that doesn't change anything. I changed the code to add
> > the event dynamically. Now there is no error message any more, but
> > Squiggle silently fails to store the click in the node object, while
> > Firefox, Opera, IE + ASV and Safari work as expected:
> >
> > <?xml version="1.0"?>
> > <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> >   "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> >
> > <svg version="1.1" xmlns="http://www.w3.org/2000/svg" onload="init()">
> >   <script><![CDATA[
> >   init = function() {
> >       var rect = document.getElementById("myrect")
> >       alert("rect: " + rect)
> >       rect.addEventListener("click",function(evt) {
> >           alert("lastClick: " + evt.target.lastClick)
> >           evt.target.lastClick = evt
> >           alert("Click stored")
> >         },false
> >       )
> >     }
> >   ]]></script>
> >
> >   <rect id="myrect" width="100" height="100" x="150" y="150"/>
> > </svg>
>
> Ah, Batik doesn’t support “expando” properties on host objects like
> Nodes.  So assigning to .lastClick is throwing an exception.
>


Mh, I mean, strictly speaking, is this conformant to  JavaScript/ECMAScript specs?  Are they saying that node objects are to be treated specially?


> If you want to store some custom information on the <rect> element, you
> can use the DOM 3 Core setUserData() method:
>
>   alert("lastClick: " + evt.target.getUserData("lastClick"));
>   evt.target.setUserData("lastClick", evt, null);
>   alert("Click stored");
>

Thanks for that tip!  I modified my test like this:


<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" onload="init()">
  <script type="text/ecmascript"><![CDATA[
  init = function() {
      var rect = document.getElementById("myrect")
      alert("rect: " + rect)
      rect.addEventListener("click",function(evt) {
          alert("lastClick: " + evt.target.getUserData("lastClick"))
          evt.target.setUserData("lastClick", evt, null)
          alert("Click stored")
        },false
      )
    }
  ]]></script>

  <rect id="myrect" width="100" height="100" x="150" y="150"/>
</svg>


It indeed works with Batik and Firefox, but not IE+ASV, Opera and Safari.  I mean, I certainly can work around this, but I still would like to know why the hell in Batik (respectively Rhino, which seems to be the DOM implementation used) the node objects aren't regular JavaScript objects!?  Is there a purpose?  Of course other than it's simply using the Java node object, which obviously can't support "expando" properties.  In my eyes that would be a pretty lazy excuse.  JavaScript is JavaScript, and Java is Java.  Other implementations manage to present the native node object wrapped properly as well.

Does anyone have an idea?

Thomas W.


Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

-- In svg-developers@..., "th_w@..." <th_w@...> wrote:
>
> [...] Batik (respectively Rhino, which seems to be the DOM implementation used)

Sorry, of course I meant "JavaScript implementation".


Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

--- In svg-developers@..., "th_w@..." <th_w@...> wrote:
>
> -- In svg-developers@..., "th_w@" <th_w@> wrote:
> >
> > [...] Batik (respectively Rhino, which seems to be the DOM implementation used)
>
> Sorry, of course I meant "JavaScript implementation".
>


It seems like it's not a Rhino issue, since this HTML runs just fine in the Lobo browser which AFAIK as well uses Rhino:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript"><!--
  init = function(){
    testnode = document.getElementById("testnode")
    testnode.myProperty = "test"
    alert(testnode.myProperty)
  }
  -->
</script>
</head>
<body onload="init()">
<p id="testnode">testnode</p>
</body>
</html>


I'll see if I can get further info on the batik-users mailing list.

Thomas W.


Re: Re: Batik doesn't allow adding JavaScript properties to node objects

by Cameron McCormack-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Cameron McCormack:
> > Ah, Batik doesn’t support “expando” properties on host objects like
> > Nodes.  So assigning to .lastClick is throwing an exception.

th_w@...:
> Mh, I mean, strictly speaking, is this conformant to JavaScript/
> ECMAScript specs? Are they saying that node objects are to be treated
> specially?

It is conformant.  Host objects need not behave the same as regular,
native objects when getting and setting properties.  (Web IDL[1] will,
when it is done, require “expando” properties to work on host objects,
for W3C specifications.)

> …
> It indeed works with Batik and Firefox, but not IE+ASV, Opera and
> Safari. I mean, I certainly can work around this, but I still would
> like to know why the hell in Batik (respectively Rhino, which seems
> to be the DOM implementation used) the node objects aren't regular
> JavaScript objects!? Is there a purpose? Of course other than it's
> simply using the Java node object, which obviously can't support
> "expando" properties. In my eyes that would be a pretty lazy excuse.
> JavaScript is JavaScript, and Java is Java. Other implementations
> manage to present the native node object wrapped properly as well.

That is how Rhino, by default, presents wrapped Java objects to
JavaScript:

  jet:/tmp/batik-1.8pre/lib $ java -jar js.jar
  Rhino 1.6 release 6 Pre 2007 11 13
  js> a = new java.lang.Object()
  java.lang.Object@133f1d7
  js> a.abc = 123
  js: "<stdin>", line 4: Java class "java.lang.Object" has no public
  instance field or method named "abc".

To allow arbitrary properties to be set on host objects exposed by
Batik, it would need to have a custom WrapFactory[2] that returns an
appropriate Scriptable[3] object which can handle both storing regular
properties (like ScriptableObject[4] can) and delegate to Java methods
(like NativeJavaObject[5] does).

It would be nice if Rhino itself could have this functionality, but it
could be implemented in Batik if someone had the time to write it.
There are various aspects of the JavaScript binding of the SVG DOM that
need to be improved, IMO.

Cameron

[1] http://dev.w3.org/2006/webapi/WebIDL/
[2] http://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/WrapFactory.html
[3] http://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/Scriptable.html
[4] http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/ScriptableObject.java
[5] http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java

--
Cameron McCormack ≝ http://mcc.id.au/

Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Cameron,

thanks so much for your in-depth information and your patience with me!  I think I'm finally beginning to understand.

--- In svg-developers@..., Cameron McCormack <cam@...> wrote:

>
> Cameron McCormack:
> > > Ah, Batik doesn’t support “expando” properties on host objects like
> > > Nodes.  So assigning to .lastClick is throwing an exception.
>
> th_w@...:
> > Mh, I mean, strictly speaking, is this conformant to JavaScript/
> > ECMAScript specs? Are they saying that node objects are to be treated
> > specially?
>
> It is conformant.  Host objects need not behave the same as regular,
> native objects when getting and setting properties.  

I wasn't really aware that host objects and native objects (also user defined objects??) can prevent me from adding or changing parameters, though this of course makes total sense.  If I'm thinking about it I wasn't really expecting it was possible to e.g. overwrite the parentNode attribte of a node object.  Please be lenient towards my ignorance.

Is it totally up to the implementation whether expando properties are allowed for SVG DOM nodes?  At least I can't see anything about this in the SVG ECMAScript binding specs:

http://www.w3.org/TR/SVGTiny12/ecmascript-binding.html

This all makes me wonder whether expando properties are so good after all.  User defined properties might e.g. cause collisions if the object's native property set might be extended in future versions.  I guess this might be the reasoning behind the setUserData features.  

Thanks again!

Thomas W.


Re: Re: Batik doesn't allow adding JavaScript properties to node objects

by Cameron McCormack-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Thomas.

Cameron McCormack:
> > It is conformant.  Host objects need not behave the same as regular,
> > native objects when getting and setting properties.  

th_w@...:
> I wasn't really aware that host objects and native objects (also user
> defined objects??)

(Yes sorry, “native objects” in ECMAScript-parlance are user created
objects.)

> can prevent me from adding or changing parameters, though this of
> course makes total sense.

Host objects are allowed to behave (mostly) however they like, according
to the ECMAScript spec.

> If I'm thinking about it I wasn't really expecting it was possible to
> e.g. overwrite the parentNode attribte of a node object. Please be
> lenient towards my ignorance.

Right, if it was a native object then the property would be writable and
you could overwrite it.

> Is it totally up to the implementation whether expando properties are
> allowed for SVG DOM nodes?

Currently, yes.  That should change when Web IDL is done and the next
version of the SVG spec (which would reference Web IDL) is published.

> At least I can't see anything about this in the SVG ECMAScript binding
> specs:
>
> http://www.w3.org/TR/SVGTiny12/ecmascript-binding.html
>
> This all makes me wonder whether expando properties are so good after
> all.

I like them. :-)  I think allowing properties that don’t clash to be set
on host objects should be required, since that behaviour would be more
in line with how native objects operate.

> User defined properties might e.g. cause collisions if the object's
> native property set might be extended in future versions.

Yes, that’s one downside.  Picking a property name that starts with,
say, an underscore seems relatively safe though.

> I guess this might be the reasoning behind the setUserData features.

I think setUserData() exists because the DOM is meant to be language
binding agnostic, and in some (most?) other languages, like Java, you
can’t extend them with arbitrary properties.  So it was added to allow
arbitrary key/value pairs to be associated with Nodes.

--
Cameron McCormack ≝ http://mcc.id.au/

Re: Batik doesn't allow adding JavaScript properties to node objects

by th_w@ymail.com :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Cameron,

--- In svg-developers@..., Cameron McCormack <cam@...> wrote:

>
> th_w@...:
> >
> > This all makes me wonder whether expando properties are so good after
> > all.
>
> I like them. :-)  I think allowing properties that don’t clash to be set
> on host objects should be required, since that behaviour would be more
> in line with how native objects operate.
>

Yes, I find them convenient, too (that's why I posted).  Bit now that I'm aware of the problems they have I'll certainly be more careful with them.

> > User defined properties might e.g. cause collisions if the object's
> > native property set might be extended in future versions.
>
> Yes, that’s one downside.  Picking a property name that starts with,
> say, an underscore seems relatively safe though.

I think it would be quite nice if the node object had a subobject that the user can mess with without worries, like

nodeObject.userProps.myProperty = "something"

Anyway, attaching properties directly to the object is still easiest to read and write.

>
> > I guess this might be the reasoning behind the setUserData features.
>
> I think setUserData() exists because the DOM is meant to be language
> binding agnostic, and in some (most?) other languages, like Java, you
> can’t extend them with arbitrary properties.  So it was added to allow
> arbitrary key/value pairs to be associated with Nodes.
>

Ah, I see - of course.  Cameron, thank you very much for this very informative course on JavaScript and the DOM!  It's great to have people around who care to share their expertise.

Thomas W.