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.

  • http://www.abdulqabiz.com Abdul Qabiz

    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

  • http://www.franciswscott.com Scotty

    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.

  • http://mannu.livejournal.com/ Manish Jethani

    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.

  • http://www.abdulqabiz.com Abdul Qabiz

    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

  • http://www.franciswscott.com Scotty

    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.

  • Tim Hoff

    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

  • http://www.abdulqabiz.com/blog/ Abdul Qabiz

    Tim, glad to know that it helped you…
    -abdul

  • http://www.laflash.org Chris Charlton

    Neat! Thanks.

  • http://blog.iconara.net/ Theo

    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#

  • http://www.abdulqabiz.com/blog/ Abdul Qabiz

    @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

  • http://www.joangarnet.com Joan Garnet

    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

  • http://www.abdulqabiz.com/blog Abdul Qabiz

    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

  • Aneesh

    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..

  • http://abdulqabiz.com/blog/ Abdul Qabiz

    @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;

  • http://www.judahfrangipane.com judah

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

  • http://www.markchoon.com Mark

    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

    • http://flexoop.com/ Gareth Arch

      Arg! Came across this same issue this weekend (figured I’d give this a try with my latest project at work). We’re currently using IE6 so I’m running across the URL length limitation. I’ve been trying trim down everything that’s unnecessary, but IE6 still keeps catching me with too much junk in the URL. Maybe I’ll try some kind of trimming function for my JS. I’m trying to contain the JS within the Flex project, but in IE6, that’s been proving difficult.

    • http://www.abdulqabiz.com/blog/ Abdul Qabiz

      I tested my work with IE6, but yeah I might have missed this particulare use-case. You can modify the code to send a long string in chunks and then run the js code?

  • http://www.jiltedreality.com Adam

    Would this work with the moteDaemon (http://sourceforge.net/projects/motedaemon/)?
    I keep getting:
    SecurityError: Error #2051: Security sandbox violation:
    errors with this example.

  • Patrice

    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!

  • Patrice

    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!

  • Patrice

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

  • syeddiwan

    Hai Abdul :-

    it’s very nice one,Right now i am doing session based flex application,so while closing the browser i need to pass the flex event,can u please guide me,
    thanks in advance

    • http://www.abdulqabiz.com Abdul Qabiz

      @syeddiwan: Sorry for late response, I believe, you can capture events (from browser) when it’s going to close and then let flex know about it. Now browser-unload event doesn’t work consistenly in all browsers, in my opinion, hence I would rather rely on different approach.

      1) Capture browser’s unload event and do the cleanup (saving data, closing session, etc).
      2) Warn user when he tries to close the browser, request him to save, exit or logoff using provided control in user-interface?
      3) Maintain a persistent connection using sockets or xmlsocket, now that might be some work and requires server-side infrastructure.

      #1 might not work in all browsers and #3 might be little too much for simple things. I see, #2 can be used to and it’s safe and sound.

      BTW! What you plan to do? I mean, a lot of people are generally confused with things “sessions” and “flex”.

      -abdul

      I believe, you can

  • px87

    Hi Abdul! thanks for the code, I tested it on flex 4 and works great!!

    I have a cuestion… I have a big class written in javascript (430 lines), I tested it with your code but it doesn’t work, do you believe that it not works because is a big string?

    Greetings.

    • http://www.abdulqabiz.com/blog/ Abdul Qabiz

      Could that be because of size limit in ExternalInterface API?

  • http://twitter.com/Roaders Giles Roadnight

    I love this. It makes what I was trying to do much simpler and neater:

    http://blog.giles.roadnight.name/2011/07/preventing-browser-from-closing-your.html

    • http://www.abdulqabiz.com/blog/ Abdul Qabiz

      That’s awesome! Keep it up.