Re: JSObject.call(), closures, JS anonymous function references etc
Hi Arne,
"Arne Vajh?j" <arne@vajhoej.dk> wrote in message
news:49bda1ae$0$90271$14726298@news.sunsite.dk...
Richard Maher wrote:
Using netscape.javascript.JSObject (LiveConnect) I want/need to pass a
Function Reference to my Java Applet so that it can either call that
directly, or pass it to a static JavaScript function that will then
redirect
the call to the appropriate anonymous function that formed a closure.
Please forgive me if the terminology is not strictly correct, but I hope
you
can still understand what I'm trying to do.
I thought the second argument to JSObject.call could be an array of
Strings
*or* Objects but trying to get a JavaScript object (or a
reference/pointer
to it) to survive the Java Applet membrane (without some sort of
serialize/deserialize) is proving difficult. Am I missing something
obvious?
Does anyone have a small example I can look at?
Maybe it's as easy as the first argument to JSObject.call can be a
JavaScript VARiable? I'll give it a go. . .
// This is called from the Applet
function jsMethod(javaInt, javaFunc) {
alert('Integer ' + javaInt);
alert('JavaFunc ' + javaFunc.toString());
javaFunc();
return;
}
It would have been slightly easier if you had told us what was happening
when this code was executed.
Appended below is the entire Applet and HTML (very tiny mickey-mouse
example). Just trying to see if the function reference survived the trip.
See below.
But I assume you have a problem with the type of javaFunc.
During testing I'd changed it to String and forgot to change it back again.
Type "Object" seems to be acceptable for a function reference/function
whatever it is.
Maybe there are some tricky way of doing this the right way.
I wish there was; looks sexy to me! (in a functionally worthwhile sense.)
But I know you can do it with eval. Pass a string from JS to Java,
pass a string from Java to JS and then call it using eval.
More on that in your other reply.
Not nice, but it will work.
Arne
Cheers Richard Maher
Here's the Java Applet: -
import java.applet.Applet;
import java.io.IOException;
import netscape.javascript.JSObject;
import netscape.javascript.JSException;
public class AnonCallApplet extends Applet {
private JSObject browser;
private static int sumNum = 0;
private int addNum;
public void init(){
try {
browser = JSObject.getWindow(this); }
catch (netscape.javascript.JSException e) {
e.printStackTrace(); }
catch (Exception e) {
e.printStackTrace(); }
}
public synchronized void javaMethod (String jsNum, Object jsFunc) {
addNum = Integer.parseInt(jsNum);
sumNum += addNum;
Object args[] = {(Object)new Integer(sumNum), jsFunc};
try {
browser.call("jsMethod", args);}
catch (JSException e){
System.out.println("Error when calling jsMethod()"); }
}
public void destroy() {
super.destroy();
}
// Yes, I don't want to synchronize around the JS call
Here's the web page. Enter something in either field an then move off. Try
several tabs and server browser instances: -
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta name="author" content="Richard Maher"/>
<meta name="description" content="JS Function and Applet Test"/>
<head>
<style>
body
{
margin: 0px;
background-color: white;
color: Black;
font-family: times;
font-size: 16px;
border: medium ridge;
}
</style>
<script type="text/javascript">
var step = 2;
var chan, myFunc;
var closures = 0;
function load() {
myFunc1 = setClosure();
myFunc2 = setClosure();
chan = document.getElementById("AnonCallApplet");
return;
}
function jsMethod(javaInt, javaFunc) {
alert('jsMethod Integer ' + javaInt);
javaFunc();
return;
}
function setClosure() {
closures++;
var myId = closures;
var lclNum = 0;
return function(){
lclNum++;
alert("Closure " + myId + " lclNum = " + lclNum);
}
}
function callApplet() {
alert(myFunc.toString());
chan.javaMethod(step, myFunc);
return true;
}
</script>
</head>
<body onload="load();">
<br /><h2>Test it</h2><hr /><br />
<form name="display" style="margin-left: 100px;">
<input
type="text"
onchange="chan.javaMethod(step, myFunc1)";
style="text-align: Left;"
name="divNode"
size=6
/>
<input
type="text"
onchange="chan.javaMethod(step, myFunc2)";
style="text-align: Left;"
name="next"
size=10
/>
</form>
<script type="text/javascript">
var appletDef = navigator.appName;
if (appletDef == "Microsoft Internet Explorer")
document.write
(
'<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ',
'width= "0" height= "0" id="AnonCallApplet">',
// '<param name="archive"
value="tier3.jar">',
// '<param name="codebase" value="http">',
'<param name="code"
value="AnonCallApplet">',
'<param name="mayscript" value="yes">',
'<param name="scriptable" value="true">',
'</object>'
);
else
document.write
(
'<object classid="java:AnonCallApplet.class" ',
'type="application/x-java-applet" ',
'width= "0" height= "0" id="AnonCallApplet">',
// '<param name="archive"
value="tier3.jar">',
// '<param name="codebase"
value="http://alpha/">',
'<param name="code"
value="AnonCallApplet">',
'<param name="mayscript" value="yes">',
'<param name="scriptable" value="true">',
'</object>'
);
</script>
</body>
</html>