Tuesday, January 31, 2012

Re: native javascript functions manipulation in java - overlay types

Any difference between your library and  http://code.google.com/p/raphaelgwt/  ? 

2012/1/31 Sebastian Gurin <sgurin@softpoint.org>
Thomas Thank you very much for your answers. You helped me al lot with my first porting of a javascript toolkit to GWT: my own version of raphaeljs.com (a cool javascript library for doing vector graphics) to gwt:

project page
http://code.google.com/p/raphael4gwt/

demo with java sources available:
http://cancerbero.vacau.com/gwt/raphael4gwtGallery/

This library was written by me in few days and from scratch.

Initially I wanted to create a layer for "doing javascript in java", so I can write javascript in java without jsni (but paying a little overhead price), like something like this:

JavaScriptObject o1 = getNativeObject();
JsUtils.put(o1, "property1", "value1");
JsUtils.put(o1, "onclick", JsUtils.FUNC(new Runnable1(){
       public JavaScriptObject run1(NativeEvent e) {
               ...
       }
});

JsUtil.put performs obj[1]=b, jsUtil.FUNC converts a Runnable in a javascript function, etc

But this seems to be impossiblein gwt. More, looking at generated sources, I see gwt compiler do a beautifull job optimizing jsni based code. Also I'm feeling very confortably programing overlay types in eclipse with gwt eclipse plugin. So I discarded my initial idea of "doing javascript in java", and I'm working with "normal" overlay types.

Thanks again, I will notify the group when my gwt4raphael library supports 100% of the raphaeljs api (neverthelessm,it is very usable right now)

Regards, and thank you again.

On Sun, 29 Jan 2012 03:23:33 -0800 (PST)
Thomas Broyer <t.broyer@gmail.com> wrote:

>
>
> On Friday, January 27, 2012 5:27:10 PM UTC+1, Sebastian Gurin wrote:
> >
> > Ok I found more or less how to do what I want, the following registers a
> > click handler in a native DOM object:
> >
> > public class DomEventTest1 {
> >
> > public static interface ClickHandler {
> >         void notifyClick(Element source);
> > }
> >
> > /** call this directly from your Entry point class */
> > public static void test(RootPanel rootPanel) {
> >
> >         //create a button using gwt DOM
> >         ButtonElement button1 = Document.get().createPushButtonElement();
> >         button1.setInnerHTML("clickme");
> >         Document.get().getBody().appendChild(button1);
> >
> >         addClickHandler(button1, new ClickHandler() {
> >                 @Override
> >                 public void notifyClick(Element source) {
> >                         System.out.println("CLICKED");
> >                 }
> >         });
> > }
> > public static native void addClickHandler(Element e, ClickHandler
> > handler)/*-{
> >         //dirty click handler registration, only for testing
> >         e.onclick=function() {
> >
> > handler.@org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.ClickHandler::notifyClick(Lcom/google/gwt/dom/client/Element;)(this);
> >         }
> > }-*/;
> >
>
> You should wrap your function in $entry() so that a) exceptions are routed
> to the GWT.UncaughtExceptionHandler and b) Scheduler.scheduleEntry and
> Scheduler.scheduleFinally run appropriately. Also, note that you could pass
> the event to your Java code as a NativeEvent:
>
> e.onclick = $entry(function(e) {
>    handler.@org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.
> ClickHandler::notifyClick(Lcom/google/gwt/dom/client/NativeEvent;)(e);
> }
>
> (you might have to tweak the code for IE, which doesn't pass the event as
> an argument but uses window.event (or should it be $wnd.event?))
>
> }
> >
> >
> > Now two quiestion about jsni.
> >
> > The first question is: the statement
> >
> > handler.@org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.ClickHandler::notifyClick(Lcom/google/gwt/dom/client/Element;)(this);
> > is a valid javascript statement? or is it some internal gwt compiler
> > language that is translated to javascript?
> >
>
> No, it's a special syntax for JSNI. It's not valid JavaScript.
>
>
> > What I would like is to be able of represent any javascript function using
> > java objects, like Runnable or other. The main problem for this is be able
> > to call a java instance method from javascript having the java class name,
> > method name and signature in strings. I would like something like:
> >
> > public static native void callJavaInstMethod(Object javaThisEl, String
> > className, String methodName, String methodSignature, Object[]params)/*-{
> >         //and here do something like:
> >
> >         javaThisEl.@${className}::${methodName}(${methodSignature})(${params})
> > }-*/;
> >
> > I tried to archieve something like this unssuccessfully with eval and
> > other hacks. A method like this, will allow me to represent any javascript
> > function using java objects. For example, instead of writing methods like
> > addClickHandler by hand, I could use an Artificial AbstractRunnable class
> > for represent javascript functions as java objects and do:
> >
> > button1.addClickHandler(new AbstractRunnable1<Element>(){
> >         public void run(Element e) {
> >                 System.out.println("CLICKED");
> >         }
> > });
> >
> > Any ideas on how to call a java instance method from native javascript
> > having all the necesary information in Strings ?
> >
>
> The GWT compiler will obfuscate all class names and method names, so it's
> not going to work. Only solution would be to create a map, something like:
>
>
>  map['org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.ClickHandler::notifyClick(Lcom/google/gwt/dom/client/Element;)']
> =
>       someObject.@org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.
> ClickHandler::notifyClick(Lcom/google/gwt/dom/client/Element;);
>
> (note that we don't call the method, we only reference it!)
> Then:
>
>    var fn = map[className + '::' + methodName + '(' + methodSignature +
> ')'];
>    fn.apply(javaThisEl, params);
>
> (but note that params would have to be a JS array if you want this to work
> in DevMode, as a Java array will be an opaque object in JS)
>
> Or of course you could do it using switch/case or if/else:
>    switch (className + '::' + methodName) {
>       case
> 'org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.ClickHandler::notifyClick':
>          javaThisEl.@org.sgx.gwtraphaljstest.client.js.test.DomEventTest1.
> ClickHandler::notifyClick(Lcom/google/gwt/dom/client/Element;)(params[0]);
>          break;
>    }
>
> However, I'd suggest you try to find another approach, as the compiler
> won't be able to prune unused code and produce an optimally optimized code.
>
> --
> You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/INg0raG3T48J.
> To post to this group, send email to google-web-toolkit@googlegroups.com.
> To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
>


--
Sebastian Gurin <sgurin@softpoint.org>

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

No comments:

Post a Comment