PDA

View Full Version : SWFObject and SetVariable


mmenti
05-03-2006, 07:36 AM
Hi,
I have a couple of questions for anyone that has some experience with SWFObject (formerly FlashObject):

- say I have a canvas attribute named "x1", and in the embed code adding am a value to it like so:

fo.addVariable("x1","some value for x1");

... I can then pick up the value of x1 from within the lxz by using "global.x1", but not by using "canvas.getAttribute("x1")". Is this normal, or am I missing something?

- I have an example where I want to change the value of a canvas attribute through a JS function later on. So I call LXBrowser.loadJS("someFunc();"), and inside "someFunc()" I try to update "x1", e.g.:

document.getElementById("lzapp").SetVariable("x1","new value for x1");

After doing this, I can't seem to pick up the new value of x1, either by referring to global.x1 or canvas.getAttribute("x1"). Is there some way to do this?

Many thanks for any help you could provide!

Mario.

d~l
05-03-2006, 08:03 AM
I use SWFObject (aka FlashObject) extensively.

And yes .. setting a global var is not the same as setting a canvas attribute. The var change has to be detected and then used to change a canvas.attribute.

..

However if you can accept using Flash 8 always, then investigate the use of externalinterface class .. which allows a var to be passed into a function within openlaszlo .. and the function can then set the attribute.

Read the laszlo-user mailing list archive .. and read the thread on Flash 8 - externalinterface class (http://news.gmane.org/gmane.comp.java.openlaszlo.user).

...

With the other method of setting of global vars (which works on Flash versions below 8, but requires use of a timed poll of var) your typical function in HTML wrapper looks like this ..


// target laszlo variable in embedded laszlo.swf

function doPassVar(args){
var sendText = args.value;
document.getElementById("lzapp").SetVariable("newText", sendText);
}



externalinterface is much neater allowing data and objects to be pushed into openlaszlo.

I am now using it for cross div communications (multiple lzx.swf in one HTML wrapper page).

mmenti
05-03-2006, 08:25 AM
Thanks d~l.

I guess the main negative consequence of insisting on Flash 8 will be the fact that Linux users will be shut out. Is anyone aware of any other considerations?

Thanks,
Mario.

d~l
05-03-2006, 08:56 AM
You could inspect this earlier demo of passing vars (http://www.laszlosystems.com/developers/community/forums/showthread.php?threadid=5407) which, if you view the HTML wrapper code, uses flashobject.js.

But this is not ExternalInterface and is passing vars (not calling a function within the openlaszlo code).

..

p.s.

more on Flash 8 on Linux .. here (http://weblogs.macromedia.com/emmy/archives/2005/12/why_isnt_there.cfm)

mmenti
05-03-2006, 09:42 AM
Very useful info, thanks a lot!

I'm trying to confirm browser/OS support with my client, and will then investigate the relevant option. From a first look the ExternalInterface API looks good, and I see you have got it working with OpenLaszlo :-)

mmenti
05-08-2006, 03:57 AM
Good news is that I can go ahead with Flash 8/ ExternalInterface.

Not so good news is that I obviously still miss something. I have code like this in my lzx script:

----------------------------------------------
function setPosResponseTexts(pos_resps) {

var resp_array = pos_resps.split("|");
for (var r = 0; r < resp_array.length; r++)
{
// do some stuff
}

}

flash.external.ExternalInterface.addCallback("setPosResps", null, setPosResponseTexts);
-----------------------------------------------

This seems to compile without error, but when I call the setPosResps function in JS, I get a Javascript error: "flashMovie.setPosResps is not a function"

My embed code looks like this:
---------------------------
fo = new SWFObject("/xyz/xyzpoc.lzx.swf", "lzapp", "800", "600", "8.0.15", "#FFFFFF", true);
fo.addParam("allowScriptAccess", "always");
fo.addParam("name", "lzapp");
fo.write("flashcontent");

... and later on ...
var flashMovie = document.getElementById("lzapp");
flashMovie.setPosResps("Some|string|values");

---------------------------


Is there something I'm missing in order to get ExternalInterface to work with OpenLaszlo?

Thanks,
Mario.

d~l
05-08-2006, 05:29 AM
(a) in your SWFObject embed do not add the argument "true" since this is used for ExpressInstall .. and this expects some code to be in first frame of movie .. see here .. (http://osflash.org/pipermail/osflash_osflash.org/2005-August/002928.html) .. so I suggest that you leave out ExpressInstall for a later stage of testing (I have not got around to trying to get this to work with OpenLaszlo and it probably is better used with a small test loader.swf).

(b) I assume that you have placed the div container before your SWFObject code

<div id="flashcontent">
</div>

and you are compiling lzx as Flash 8.

(c) Otherwise .. looks o.k.

(d) This was the simple callback test code suggested by pw in the laszlo-user mail list thread ..

callback.lzx


<canvas debug="true">
<script>
flash.external.ExternalInterface.addCallback("testing", null, function () { Debug.write("Hello") })

LzBrowser.loadJS('document.getElementById("lzapp").testing()')
</script>
</canvas>


Compile as Flash 8 .. just to test the ExternalInterface API using debugger (bypassing SWFObject).

Does this work .. displays "Hello" in debugger?

mmenti
05-08-2006, 06:50 AM
(a) in your SWFObject embed do not add the argument "true" since this is used for ExpressInstall .. and this expects some code to be in first frame of movie .. see here .. (http://osflash.org/pipermail/osflash_osflash.org/2005-August/002928.html) .. so I suggest that you leave out ExpressInstall for a later stage of testing (I have not got around to trying to get this to work with OpenLaszlo and it probably is better used with a small test loader.swf).


Ok, I've removed this, but doesn't seem to make a difference to the current issue.


(b) I assume that you have placed the div container before your SWFObject code
<div id="flashcontent">
</div>


Yes.


and you are compiling lzx as Flash 8.


Yes.


(c) Otherwise .. looks o.k.
(d) This was the simple callback test code suggested by pw in the laszlo-user mail list thread ..

callback.lzx


<canvas debug="true">
<script>
flash.external.ExternalInterface.addCallback("testing", null, function () { Debug.write("Hello") })

LzBrowser.loadJS('document.getElementById("lzapp").testing()')
</script>
</canvas>


Compile as Flash 8 .. just to test the ExternalInterface API using debugger (bypassing SWFObject).

Does this work .. displays "hello" in debugger?

Yes, this works.. both as a standalone lzx, or when I type it into the debugger manually.. strange. Just to be sure it's not something really stupid I checked to make sure nothing is cached, or any spelling mistakes anywhere, but can't seem to find anything.

mmenti
05-08-2006, 07:35 AM
One additional point: when enabling debug on the canvas, when I go through the SOLO deployment wizard, I get these debug errors (I don't get them when compiling within the "normal" compilation window):

WARNING: xeroxpoc.lzx:115: reference to undefined variable 'flash'
WARNING: xeroxpoc.lzx:115: undefined object does not have a property 'external'
WARNING: xeroxpoc.lzx:115: reference to undefined property 'external'
WARNING: xeroxpoc.lzx:115: undefined object does not have a property 'ExternalInterface'
WARNING: xeroxpoc.lzx:115: reference to undefined property 'ExternalInterface'
WARNING: xeroxpoc.lzx:115: undefined object does not have a property 'addCallback'

I see from the laszlo-user group that you (d~l) have come across the same, can you remember what the cause of this was, and whether it was a real issue?

Thanks,
Mario.

d~l
05-08-2006, 07:51 AM
I saw those warning messages when I thought that I had compiled lzx as Flash 8 .. but in fact it was still Flash 7 and so not recognising the externalinterface class (which is Flash 8 only).

Check the version ..

When compiling your lzx go to the dev console at bottom of page and choose Flash 8 > compile.

I have produced a working demo in zipped attachment below .. testextint.zip .. which follows your application structure.

_______________


Added note 1 .. I do not use the SOLO deployment wizard so I'll try that to see if there is some error in compiling Flash 8.

_______________

Added note 2 .. after running the demo I tried a command in debugger to inspect canvas

Debug.inspect(canvas);

This does not display canvas attributes ..

and when I clicked again on the link "pass this string to OpenLaszlo debugger" I get "undefined" as passed string.

So there is some quirk/bug here which needs to be pinned down.

d~l
05-08-2006, 08:18 AM
I tried compiling demo in SOLO mode / Flash 8 but I'm getting a tomcat exception error ..

"org.apache.jasper.JasperException: Unable to compile class for JSP"

which might suggest that the externalinterface class is not being compiled.

But .. if using SWFObject then SOLO wizard becomes redundant .. now, with SWFObject, I never need to deploy using SOLO wizard or embed.js.

mmenti
05-08-2006, 08:25 AM
Well, this is just the kind of stupid thing I thought it may be....

Turns out that when clicking on the SOLO deploy button, the compiler doesn't use the runtime target that's specified in the radio group above, but uses the compiler.runtime.default setting in lps.properties instead. So even if you select swf8 on the screen, if your default compiler option is swf7, then that's what the SOLO wizard compile uses.

So I changed the setting in lps.properties to ..
compiler.runtime.default=swf8

... and now everything works.

Many thanks for your help! Hopefully this will get me on my way now :-)

mmenti
05-08-2006, 08:43 AM
.... ok, one more question, hopefully quick:

If not using the SOLO deploy wizard, what's the quickest way to complile lzx to Flash 8?

Cheers,
Mario.

d~l
05-08-2006, 09:41 AM
I use the compile > swf8 button in dev console .. not using the Server or SOLO buttons

but you can also add &lzr=swf8 to the URL

e.g.


http://localhost:8080/openlaszlo-3.2/my-apps/externalinterface/testextint.lzx?debug=true&lzr=swf8

mmenti
06-16-2006, 04:54 AM
Ok, my app with SWFObject and ExternalInterface is now all working and tested, so no problems there..

The next thing will be trying to get ExpressInstall to work with OpenLaszlo - has anyone (d~l?) successfully done that yet?

Thanks!
Mario.

d~l
06-16-2006, 05:47 AM
I have not yet tackled adding ExpressInstall .. but I understand that the required detection actionscript must be placed in frame 1 of the SWFObject embedded movie.

OpenLaszlo does not have a conventional frame timeline (everything is in one frame it seems), so I'm guessing that the ExpressInstall detector might best be placed in a separate preloader swf (launched before launching the OpenLaszlo movie).

Possibly this preloader (if compiled in Openlaszlo) can include the ExpressInstall actionscript.

This post referring to earlier FlashObject (http://osflash.org/pipermail/osflash_osflash.org/2005-August/002928.html) seems relevant. And, from that post read this (http://blog.deconcept.com/2005/08/13/using-flash-player-express-install-with-flashobject/).

If that posted ExpressInstall class cannot be compiled into OpenLaszlo script then other opensource compilers can be used.

MTASC + SWFmill .. or the newer haXe (http://www.haxe.org).

d~l
06-16-2006, 11:57 AM
I raised a question on ExpressInstall in SWFObject mail list .. got this reply ..


On 6/16/06, Geoff Stearns < geoff@deconcept.com> wrote:
the express install code with SWFObject doesn't use a class anymore because of preloading issues...

now there is just an include file with some code in it. you should just insert this code into your movie so that it runs first. while i haven't used any of the open source projects to create an express install swf, you should just be able to put this code into the main() method that is executed when your swf loads... (i'm not really all that familiar with how they work, but i think mtasc works like this)

as long as your main class will load in flash player 6, you'll be fine. In the future, if swf files get to be too incompatible with older players, there may be a need to compile a separate swf file for the express install stuff, and if you like, you can set up your
projects like this now.


but I can't yet get the expressinstall.as (from swfobject distribution) to compile as script in openlaszlo .. lzx compiler doesn't like the : syntax.

Compilation errors

expressinstall.lzx:37:32: Syntax error: the token ":" was not expected at this position. Was expecting {

So I might try compiling in haXe.

harunhasdal
10-19-2006, 07:34 AM
Hi

I m using lps 3.2 and flashplayer 9 .

I was trying to use lzSetCanvasAttribute to access the result of browser scripts. The main problem of that turned out to be asynchronous execution of browser script and laszlo scripts. laszlo scripts don't wait for the results of LzBrowser.loadJS() method.

However after i read this thread i was a bit hopeful that using SWFObject and externalinterface may solve the problem. Because somewhere in the forum i read that there is no need to poll the canvas attributes if you set them with externalinterface.

But i could not get it working. I have the same timing problem on my example.

My test is as follows:



<canvas debug="true" proxied="false" id="canvas1">
<attribute name="evalRes" type="string" value="initial"/>
<script>
function processEvalResult(result) {
Debug.write("processEvalResult called with " + result);
canvas1.evalRes = result;
Debug.write("evalRes in processEvalResult: " + canvas1.evalRes);
}

flash.external.ExternalInterface.addCallback("processEvalResult", null, processEvalResult);
</script>


<button id="btn1" text="Button1" >
<method event="onclick">
LzBrowser.loadJS("callCanvasMethod(eval('1 == 1'));");
Debug.write("evalRes after loadJS: " + canvas1.evalRes);
</method>
</button>
</canvas>



My html wrapper page code is as follows:


<html><head>
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<title>DENEME</title>
<script type="text/javascript" src="swfobject.js">
</script>
<script type="text/javascript">
function callCanvasMethod(arg)
{
var myFlashMovie = document.getElementById("canvas1");
myFlashMovie.processEvalResult(arg);
}
</script>
</head>

<body link="#042d56" alink="#4b4b4b" vlink="#4b4b4b" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
<div id="flashcontent">
<strong>You need to upgrade your Flash Player</strong>
</div>

<script type="text/javascript">
// <![CDATA[
var so = new SWFObject("deneme.lzx.swf", "canvas1", "100%", "100%", "8", "#FF6600");
so.addParam("scale", "noscale");
so.addParam("swliveconnect", "true");
so.write("flashcontent");
// ]]>
</script>
</body>

</html>


Note : I compiled the lzx file with option ?lzr=swf8

Still i think there is some point i am missing. I hope you can see the point and help me.

Note : Any other way to get the result of javascript eval() function from laszlo also can help.

regards

d~l
10-20-2006, 01:24 AM
You have most of the code correct .. the ExternalInterface callback is certainly working.

Here are the changes I would look at.

First in the lzx code:-

Do not use "canvas1" as the path to objects and properties in the inner code.

e.g. canvas1.evalRes

The canvas ID is only needed for the HTML code to target the movie.
So all inner references should just be "canvas".

canvas.evalRes

If you leave out the canvas ID in the canvas tag the default ID is "lzapp" (burned in by the lzx compiler).

But if you deploy multiple SWFObjects in the HTML wrapper page a unique canvas ID
is required for each embedded movie (otherwise they would all be identified as "lzapp" - confusing).

To change the evalRes canvas attribute you can also use setAttribute().

I'm not sure why you need to be using eval() in this example (although it works).

Another (longhand) way is to eval a result script to be concatenated to use as function argument,
like this (you can shorten it, but you get the general idea):-

var m = "1";
var n = "1";

if (m == n) {
var arg = "true";
} else {
var arg = "false";
}

Debug.write(arg);
var script = ("'callCanvasMethod(\"" + arg + "\")'");
Debug.write(script);
LzBrowser.loadJS(script);


And now the HTML wrapper page:-


View the source of this example page:-

ExternalInterface (http://blog.deconcept.com/code/externalinterface.html).

Note that this SWFObject parameter is now redundant
(swliveconnect previously needed for FSCommand calls in earlier Flash versions)

so.addParam("swliveconnect", "true");

Set Flash version to "8.0.15"

Add this parameter

// need this next line for local testing, it's optional if your swf is
// on the same domain as your html page
so.addParam("allowScriptAccess", "always");


Hope that these work.

_______________________

p.s.

To answer an earlier point in this thread on using ExpressInstall,
the latest beta release of SWFObject 2.0 uses a separate movie (1,500 bytes)
for controlling ExpressInstall.

SWFObject v1.4.4 is the latest stable build (http://blog.deconcept.com/swfobject/swfobject1-4.zip).

SWFObject v2.0 is available for beta testing (http://blog.deconcept.com/code/swfobject2.0/).

harunhasdal
10-20-2006, 02:56 AM
Much thanks for the reply. Now that i got a better understanding of the mechanism but i could not solve the problem. I made the modifications you suggested but again i saw that lzx script does not wait for the loadJS() call to finish its work. On my example the button's onclick method finishes before the execution of function processEvalResult which is called by browser js.

Note : i must use eval() to evaluate a string expression that is read from a configuration structure.

I m sending my example as attachment. Maybe it can describe my problem better than me :)

Thanks again.

d~l
10-21-2006, 07:27 AM
On the problem that your Debug.write is running faster than the callback from HTML javascript ..

this arises because the Flash script and javascript are running asynchronously ..

Surely the simple solution is to execute your required functions after you receive the callback ..


<?xml version="1.0" encoding="UTF-8" ?>
<canvas debug="true" proxied="false" id="canvas1">
<attribute name="evalRes" type="string" value="initial"/>
<script>

function processEvalResult(result) {

Debug.write("processEvalResult called with " + result);
canvas.setAttribute("evalRes", result);
Debug.write("evalRes in processEvalResult: " + canvas.evalRes);
canvas.execute_on_callback();
}

flash.external.ExternalInterface.addCallback("processEvalResult", null, processEvalResult);
</script>

<simplelayout axis="y" />
<button id="btn1" text="Button1" >
<method event="onclick">
LzBrowser.loadJS("callCanvasMethod(eval('1 == 1'));");
</method>
</button>

<method name="execute_on_callback">
Debug.write("evalRes after loadJS -> callback: " + canvas.evalRes);
</method>
</canvas>

...

On your problem re: use of eval() ..

beware that eval() in Flash may not be fully compliant with eval() usage in parent javascript ..
search this forum for confirmation ..
so one option is to use LzBrowser.loadJS() to pass expressions
to be evaluated in the parent javascript ..
and eval() result passed back to lzapp.

gcleaves
12-15-2006, 08:37 AM
Is there a way to have the HTML wrapper served from domainA and the laszlo swf movie served from domainB and have the two objects speak to each other via externalInterface? It appears that the HTML wrapper's javascript is only allowed to access the swf externalInterface when the two objects come from the same domain.

I tried putting crossdomain.xml into the root of each server but no luck.

d~l
12-15-2006, 09:19 AM
I believe that ExternalInterface class usage is restricted to same domain .. but I'm not sure on this. Check out this at Adobe site. (http://livedocs.macromedia.com/labs/as3preview/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000176.html) Perhaps you could try defining the (trusted) URL to the remote swf in Global Security Settings Panel (http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html)??

See later added postscripts below ..

....

Meanwhile, an early stage test is to use remoting (and other) features in haXe (http://haxe.org) compiled movies.

I have successfully loaded haXe compiled resources (Flash 8 *.swf files) into OpenLaszlo canvas.

And this leads to the possibility of remoting (such as in AMFPHP) for cross domain communications.

See haXe remoting tutorial here. (http://haxe.org/tutos/remoting/client_server)

I have not been able to reverse this process and load OpenLaszlo compiled *.swf files into haXe host movies via loadMovie().

__________________________

postscript ..

A bit of googling found this article (http://livedocs.macromedia.com/labs/as3preview/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000158.html) confirming that cross-domain scripting (in Flash) is only available in AS3 (Flash 9).

Since haXe compiles to Flash 9, and OpenLaszlo does not yet compile to Flash 9, one possible route to follow is to build a cross-domain remote scripting gateway in haXe.

So you have ..

domain_A
lzx_A.swf (Flash 8)
haxe_A.swf (Flash 9)


domain_B
lzx_B.swf (Flash 8)
haxe_B.swf (Flash 9)


haxe_A.swf connects to haxe_B.swf (cross-domain)
lzx_A.swf connects to haxe_A.swf (local domain)
lzx_B.swf connects to haxe_B.swf (local domain)

__________________________

second postscript ..

After digging around on this subject it seems that there might be a simpler method of remote scripting (crossdomain) to maintain states of both swf objects without need for page reloading, and avoiding use of haxe Flash9 gateway as suggested above.

i.e. using an HTML-in-iframe proxy which passes data to the openlaszlo swf in parent HTML wrapper.

The HTML document embedded in iframe has the same function as the proposed haxe.swf gateway.

This approach only requires HTML + Javascript as the conduit between both swf files.
__________________________