« Things I want to see in Adobe Apollo | Main | JavaScript injection through ActionScript »

June 16, 2006

A MXML component that embeds JavaScript in html

I know subject line is confusing but I am not able to think a better one. I have written a Adobe Flex 2.0 component(JavaScript.as), which can be used as MXML tag in Flex 2.0 applications. You can write JavaScript code as text of this MXML tag. When your application loads, all that JavaScript code would be exported to HTML container's context.

Confused? Let code speak rather than me :)

Sample MXML application using this component (test.mxml):-


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="com.abdulqabiz.utils.*" width="100%" height="100%">
<JavaScript>
<![CDATA[
var myName = "Abdul Qabiz";
function saySomething (str)
{
alert (str);
}
function sayHelloWorld ()
{
alert ("Hello World!");
}
]]>
</JavaScript>
<mx:Script>
<![CDATA[
import flash.external.ExternalInterface;
private function invokeSayHelloWorld ()
{
ExternalInterface.call ("sayHelloWorld");
}
]]>
</mx:Script>
<mx:Button label="invoke javascript sayHelloWorld () function" click="invokeSayHelloWorld ()"/>
</mx:Application>

HTML code that embeds test.swf(output of above code):-


<html>
<head>
<!-- swfobject -->
<script type="text/javascript" src="http://blog.deconcept.com/swfobject/swfobject_source.js"></script>
</head>
<body>
<div id="flashcontent" class="playerContent" >You don't have Flash Player 9.</div>
<script type="text/javascript">
var swfObj = new SWFObject ("JavaScriptComponentTest.swf","JavaScriptComponentTest", "300", "300", "9", "#C0D4DD", true);
swfObj.write("flashcontent");
</script>
<a href="javascript:void(0)" onclick="saySomething ('hey')" >invoke saySomething ()</a><br />
<a href="javascript:void(0)" onclick="sayHelloWorld ()" >invoke sayHelloWorld ()</a><br />
<a href="javascript:void(0)" onclick="alert (myName);">show myName </a><br />
</body>
</html>

See an example Or Download (zip 133kb includes the SWF).

The code is available under the MIT license.

Disclaimer: I have only tested this in FireFox on Windows. So please drop a comment, if doesn't work in your system.

Update:
March 6, 2007 - Fixed a bug, which popped-up after I implemented comment removal feature. Thanks to Joan for point it out.
March 5, 2007 - Library has been updated, it can now handle comments in JavaScript code. It would basically remove all comments before injecting it in HTML container.

Posted by Abdul Qabiz at June 16, 2006 03:31 AM

Comments

Subject of this post could be either of these:-

- JavaScript injection through ActionScript
- JavaScript injection through MXML
- Inject JavaScript through MXML or JavaScript


Listing, so that search-engines can index this comment and show this entry..

-abdul


Posted by: Abdul Qabiz at June 16, 2006 04:50 AM

Really cool, I thought I would be the only one to see usefullness in something like this. Though I dont use your version, I have something very similar.

Question though, In my component I had to strip out "\n", "\r", etc.... how did you get around this? navigateToURL decode this stuff for you? ExternalInterface did not.

One other thing to think about, should the script keep track of what it has sent to HTML already? What if a component contains JavaScript and you need two instances of the component? Would that send the script twice? If so, are two sayHello() functions allowed in javascript? Didnt test if thats the case but I have a static array to keep track of all source properties so it only sends it once.

Posted by: Scotty at June 16, 2006 10:56 AM

Neat.

About the subject, you'd have a much better chance if you linked to the blog entry with the various subject lines as the anchor text.

Posted by: Manish Jethani at June 16, 2006 05:29 PM

Manish, remember this is the idea I discussed long. I wanted that compiler folks or FB team do that...

Anyways, hope this idea has some use-cases. I have some in my mind. I would post some examples.

Scotty, I tried using ExternalInterface then I realized I don't need it because it is one way call. And I also faced issues you mentioned.

I have not checked but you can create multiple instances of JavaScript component and inject scripts...It should work, I am just using "eval()" to make it work.

If you try to inject a function, which is already present. New injection would override the things...


-abdul

Posted by: Abdul Qabiz at June 16, 2006 08:16 PM

ah, I didnt know if you specified two of the same functions in javascript it would just override the previous one.

Use cases...
if your component relies on javascript and dont want to have to make sure the calling page contains a special wrapper.
Another being a way to hide your javascript logic, kinda of an encryption method. Im not sure if there are Javascript debuggers that pay attention to eval()'ed calls.

Posted by: Scotty at June 16, 2006 11:07 PM

Thanks for the code sample Abdul. I used your class to inject javascript that sets the focus to an swf, instead of modifying the html wrapper page. I think that mySWF.focus() only works in IE, but that's better than nothing. At least now the function wont be accidentally overwritten by Flex Builder.

Best Wishes,
Tim Hoff

Posted by: Tim Hoff at June 27, 2006 09:02 AM

Tim, glad to know that it helped you...

-abdul

Posted by: Abdul Qabiz at June 30, 2006 01:09 AM

Neat! Thanks.

Posted by: Chris Charlton at June 30, 2006 05:40 AM

Interesting idea, however, there is a much better way to do this than using getURL, check out my article on how to (ab)use the ExternalInterface to execute arbitrary JavaScript: Abusing the ExternalInterface


yours,


T#

Posted by: Theo at March 5, 2007 05:47 PM

@Theo - I don't exactly remember why I used navigateToURL () or getURL ().. But there were some issues around it so I used navigateToURL (..)

May be it's newline character or comments or could be anything.. For simple statements/expressions ExternalInterface works.. but complex ones, it doesn't..

Please try to port one my examples, in separate post , using your technique and see if it works..

Thanks

-abdul

Posted by: Abdul Qabiz at March 5, 2007 06:18 PM

The last update would make this crash:


<JavaScript>
<![CDATA[
location.href = "http://www.yahoo.com";
]]>
</JavaScript>

Mabybe you could evaluate that the double slash is not between quotes.
Cheers

Posted by: Joan Garnet at March 5, 2007 11:05 PM

Thanks Joan,

I am not very good in RegExp, I have fixed it anyway. I am going to sit down and write down all the use-cases and write proper regexp patterns.

I guess, I would end up writing some kind of laxer/grammar :)

-abdul

Posted by: Abdul Qabiz at March 6, 2007 03:06 AM

hi abdul...

i am using eclipse with flex plugin...but i get an error saying "could not resolve to component implentation....where should i put JavaScript.as that u have mentioned and how should i run it in eclipse..

Posted by: Aneesh at June 4, 2007 10:37 PM

@Aneesh: Put JavaScript.as in com/abdulqabiz/utils folder inside your project. Then you need import it or declare it in xml namespace

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:utils="com.abdulqabiz.utils.*" ....

If you are using JavaScript in ActionScript, import it:-

import com.abdulqabiz.utils.JavaScript;

Posted by: Abdul Qabiz at June 5, 2007 09:34 PM

This is sweet! Do you know what browsers this works in?

Posted by: judah at June 8, 2007 03:28 PM

Hi,

I noticed this very peculiar behaviour:

try putting this in a javascript function and execute it as you said:

alert ("aaaaaaaabbaaaaasdddddddddddd2aaaaaaaaaaaaaaa1sasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1");

I got differing results in different browsers. It basically does not work in IE6. All other javascript functions don't work also if on the same flex app or html page.
However this works in IE7 and Firefox. It only works in IE6 if the piece of code above is put into a normal html page and not executed through Flex.

wondering what's going on and if there is a workaround to the limit of characters in a string

Posted by: Mark at June 14, 2007 08:17 AM

Would this work with the moteDaemon (http://sourceforge.net/projects/motedaemon/)?

I keep getting:

SecurityError: Error #2051: Security sandbox violation:

errors with this example.

Posted by: Adam at November 10, 2008 06:10 AM

hi,

thanks for this code. i'm trying to integrate multiple javascript files into a flex application. i copied the code from your javascript.as file and tried to use the javascript tag in a separate mxml component file but it didn't work. it says that it could not resolve to a component implementation.

do you know what i could be doing wrong?

hopefully you're still getting messages about comments from this post!

thanks!

Posted by: Patrice at November 21, 2008 06:23 AM

hi,

so i fixed the problem that said it could not resolve to a component implementation (i think), by using but now it has a problem with "packages cannot be nested" in javascript.as

do you know what i could be doing wrong?

thanks!

Posted by: Patrice at November 21, 2008 07:46 AM

hi,

nevermind. i had just named the file differently from the class. it's all fixed now. thanks for the code!

Posted by: Patrice at November 21, 2008 07:52 AM

Post a comment




Remember Me?


Please enter the security code you see here

(you may use HTML tags for style)