views:

2373

answers:

2

I'm developing an invisible Java Applet, that will be controlled entirely from JavaScript.

I can call the applet's Java methods easily, and I can call JavaScript methods from within the applet by using netscape.javascript.JSObject.getWindow(this).call().

But in order to register a JavaScript callback in the applet, I guess I would need an JavaScript function object of some sort.

I would like to do:

public void registerCallback( SomeJavascriptFunction func ) { ... }

Which I could call from Javascript:

myapplet.registerCallback(function(){ alert("called back"); });

So I could call this function in later code:

func.call( ... );

Does something like this exist? How can I do this?

Rigth now I'm thinking of creating some Javascript to handle this callback mechanism instead of doing so from the applet.

+1  A: 

I am brand new to Java <-> JavaScript communication, as I planned to explore it this week. A good opportunity here... :-)

After some tests, it seems you cannot pass a JS function to a Java applet. Unless I am doing it the wrong way...

I tried:

function CallJava()
{
  document.Applet.Call("Does it work?");
  document.Applet.Call(function () { alert("It works!"); });
  document.Applet.Call(DoSomething); // A simple parameterless JS function
  document.Applet.Call(window.location);
}
function DumbTest(message, value)
{
  alert("This is a dumb test with a message:\n" + message + "\n" + value);
}

where Call is (are) defined as:

public void Call(String message)
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  String[] arguments = { "Call with String", message };
  win.call("DumbTest", arguments);
}

public void Call(JSObject jso)
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  String[] arguments = { "Call with JSObject", jso.toString() };
  win.call("DumbTest", arguments);
}

When I pass a JS function (all tests in FF3), I get a null on the Java side.

Note that the following Java routine allows to display the JS code of DumberTest function!

public int Do()
{
  JSObject win = (JSObject) JSObject.getWindow(this);
  JSObject doc = (JSObject) win.getMember("document");
  JSObject fun = (JSObject) win.getMember("DumberTest");
  JSObject loc = (JSObject) doc.getMember("location");
  String href = (String) loc.getMember("href");
  String[] arguments = { href, fun.toString() };
  win.call("DumbTest", arguments);
  return fun.toString().length();
}

To the point: I made a JS function:

function RegisterCallback(cbFunction)
{
  var callback = cbFunction.toString(); // We get JS code
  var callbackName = /^function (\w+)\(/.exec(callback);
  document.Applet.RegisterCallback(callbackName[1]);
}

I extract the name of the JS function from the toString result and pass it to Java applet. I don't think we can handle anonymous functions because Java call JS functions by name.

Java side:

String callbackFunction;
public void RegisterCallback(String functionName)
{
  callbackFunction = functionName;
}
void UseCallbackFunction()
{
    if (callbackFunction == null) return;
    JSObject win = (JSObject) JSObject.getWindow(this);
    win.call(callbackFunction, null);
}
PhiLho
+1  A: 

win.eval() will call a predefined javascript.

String callbackFunction;
public void RegisterCallback(String functionName)
{
  callbackFunction = functionName;
}
void UseCallbackFunction()
{
    if (callbackFunction == null) return;
    JSObject win = (JSObject) JSObject.getWindow(this);
    win.eval(callbackFunction);
}
RealHowTo
eval is more generic, hence less efficient than call for this precise task, and it is more complex to pass parameters to the JS function.
PhiLho