Archive for the ‘ActionScript and JavaScript Sitting In A Tree…’ Category

The onHashChangeManager Class

Monday, April 26th, 2010

The onHashChangeManager Class is used to register and listen for the window.onhashchange event in the swf.

package com.tadSrc.tadsClasses
{

	import flash.events.EventDispatcher;
	import flash.external.ExternalInterface;
	import flash.events.TimerEvent;
	import flash.events.Event;
	import flash.utils.Timer;

	public class onHashChangeManager extends EventDispatcher
	{

		public var functionToCall:Function;

		public function onHashChangeManager(func:Function = null, lag:Number = 500)
		{

			functionToCall = func;
			var t:Timer = new Timer(lag, 1);
			t.addEventListener(TimerEvent.TIMER_COMPLETE, ini, false, 0, true);
			t.start();
		}

		private function ini(e:TimerEvent):void {

			if (ExternalInterface.available) {

				ExternalInterface.addCallback("onHashChangeCallback", callFunc);
				makeLevelOneMasterTalk("onHashChangeForSWF", "onHashChangeCallback", getIdByIndex());
				establishOnHashChangeListener();

			}

			e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, ini);

		}

		private function callFunc(currentHash:String = ""):void {

			if (functionToCall != null) functionToCall(currentHash);
			this.dispatchEvent(new Event(currentHash));
		}

		private function establishOnHashChangeListener():void {

			var javaScript:XML =
			<script>
			<![CDATA[
			function () {

				window.onhashchange = function (e) {

					var thee = (e != undefined) ? e : event;
					var afthash = new RegExp("[\#]{1}[a-z0-9\,\-\.\/]{1,}", "i");
					var thehashword = (window.location.toString().match(afthash)) ?
						window.location.toString().match(afthash).toString().replace("#", "") : "";

					onHashChangeForSWF(thehashword);
				};

			}
			]]>
			</script>;

			if (ExternalInterface.available) ExternalInterface.call(javaScript);

		}

		private function makeLevelOneMasterTalk(nameToBe:String, funcIs:String, idIs:String):void
		{

			/* used to create a javascript function that acts as the callBack function itself. */

			var masterTalkBuild:String =
			"<script><![CDATA[function(){"+nameToBe+" = function"+
			"() { var fcontenter;"+
			"try {fcontenter=window.document.getElementById('"+idIs+"');}catch(e) {"+
			"try {var theflash='"+idIs+"';fcontenter=window.document.theflash;}catch(e) {var movie='"+idIs+"';"+
			"if (navigator.appName.indexOf('Microsoft')!=-1 || navigator.appName.indexOf('MSIE')!=-1) {"+
			"if (window.document[movie]){fcontenter=window.document[movie];}else{fcontenter=window[movie];};"+
			"}else {if (document.embeds[movie]){fcontenter=document.embeds[movie];}else"+
			"{fcontenter=document[movie];};}}}"+
			"if (arguments && arguments.length > 0) {fcontenter['"+funcIs+"'].apply(fcontenter, arguments);}"+
			"else{fcontenter['"+funcIs+"']();} }; }]]></script>";

			if (ExternalInterface.available) {

				var builtFunction:XML = new XML(masterTalkBuild);

				ExternalInterface.marshallExceptions = true;
				ExternalInterface.call(builtFunction);
			}

		}

		public function getIdByIndex(index:Number = 0):String
		{
			var outed:String = "";
			var idofswfobject:XML =
			<script>
			<![CDATA[
			function (indexr) {

				function getid(indexer) {
					var objects;
					var r = "";
					try {

						 (document.getElementsByTagName("object")) ?
						 objects = document.getElementsByTagName("object")[indexer] :
						 objects = document.getElementsByTagName("OBJECT")[indexer];

						 if (objects.hasAttribute("id") && !objects.id) {r=objects.getAttribute("id");}
						 if (objects.id && !objects.hasAttribute("ID")) {r=objects.id+"";}
						 if (objects.hasAttribute("ID")) {r=objects.getAttribute("ID");}

					}catch (e) {

						  (document.getElementsByTagName("object")) ?
						  objects = document.getElementsByTagName("object")[indexer] :
						  objects = document.getElementsByTagName("OBJECT")[indexer];

						if (objects && objects.outerHTML) {

							 var ohtml=objects.outerHTML.toString();
							 var idfind = new RegExp("id[ ]{0,}=[ ]{0,}[ a-zA-Z0-9\_\"]{1,}", "i");
							 var ridid = new RegExp("id", "i");
							 var rideq = new RegExp("[=\"]{1,}", "ig");
							 var ridspace = new RegExp("[ ]{1,}", "g");
							 var nocodeBase = new RegExp("codeBase|classid|height|width", "ig");

							if (ohtml.match(idfind)) {
								r =
								ohtml.match(idfind).toString().replace(ridid, "").replace(rideq,
                                                                "").replace(ridspace, "").replace(nocodeBase, "");
							}else{r = "";}
						}else {r = "";}

					}
					return r;
				};

			return(getid(indexr));

			}
			]]>
			</script>;

			if (ExternalInterface.available) {
				outed = ExternalInterface.call(idofswfobject, index);
			}

			return outed;

		}

	}
}

Example use of the onHashChangeManager.
This example will use it to allow draw commands to be passed to the swf from the hash.

package
{

	import flash.display.Sprite;
	import com.tadSrc.tadsClasses.onHashChangeManager;

	public class graphicsChangeWithHash extends Sprite
	{

		private var hashDispatch:onHashChangeManager;

		public function graphicsChangeWithHash() {

			hashDispatch = new onHashChangeManager(hashHasChanged);
			this.graphics.lineStyle(1, 0x000000);
			this.graphics.drawCircle(0,10,20);

		}

		private function hashHasChanged(hash:String):void {

			var specs:Array = hash.split(",");
			var command:String = specs.shift();
			var rest:Number = specs.length;
			var args:Array = [];
			for (var i:int = 0; i < rest; i++)
			{
				args.push(specs[i]);
			}

			this.graphics[command].apply(this, args);

		}

	}

}

You can also listen for the individual hash values:


hashDispatch.addEventListener("drawCircle,0,10,20", hashChangeHandler);

private function hashChangeHandler(e:Event):void {
     hashHasChanged(e.type);
}

Embedding JQuery inside of your SWF.

Friday, March 26th, 2010

Yes! yes you can! And it is fairly simple. In the code below I’ll show you how to embed JQuery-1.3.2min inside of a SWF so that it is ready to be used in the wrapper.

The major benefit is that by embedding  JQuery inside a SWF you save about 35kb worth of space. JQuery-1.3.2min on its own is 56kb, the code below compiles to about 20.7kb!

To do the actual embedding we use the Embed Flex meta data tag. You can also use Embed in the Flash IDE, you just need to point it to the correct library path. CS4 should prompt you with the path automatically.

package
{

        import flash.display.Sprite;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
        import flash.external.ExternalInterface;

        public class jQueryInside extends Sprite
        {

                //jquery 1.3.2 min embedded as an octet stream
                //the JQuery Class is a ByteArray
                [Embed(source="js/jquery.js", mimeType="application/octet-stream")]
                private var JQuery:Class;

                public function jQueryInside() {

                        //a little delay to allow the DOM to be ready
                        var t:Timer = new Timer(400, 1);
                        t.addEventListener(TimerEvent.TIMER_COMPLETE, giveJQuery, false, 0, true);
                        t.start();

                }

                private function giveJQuery(e:TimerEvent):void {

                        //convert the ByteArray to a String
                        var jq:String = new JQuery().toString();

                        //a string is used to insert the jquery contents into a function wrapped in xml cdata tags
                        var outJq:String = "<script><![CDATA[function () {"+jq+"}]]></script>";
                        // and wrapp the javascript in a function and in xml for ease of passage

                        //turn it into true XML
                        var theJQuery:XML = new XML(outJq);

                        //use the ExternalInterface to call the wrapped function wich thereby applies jQuery to the DOM
                        if (ExternalInterface.available) ExternalInterface.call(theJQuery);

                        //jquery is ready to be used in the HTML page at this point

                        //clear the event listener
                        e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, giveJQuery);

                }

        }

}


A basic HTML page using the above SWF would look like this:

<html>
<head>
</head>
<body>
<script type="text/javascript">
    function doAnimation() {
        $("#someDiv").animate({"left": "-=50px"}, 3000);
    }
</script>
<script type="text/javascript" src="swfobject.js"></script>
<div id="someDiv" style="width:100px;background:black;position:relative;left:5px" onclick="doAnimation()">Some Text</div>
<div id="theSWF"></div>

<script type="text/javascript">
  //<![CDATA[

	var flashvars = {};
	var params = {};
	var atts = {};

	params.menu = "true";
	params.quality = "high";
	params.wmode = "opaque";
	params.swfliveconnect = "true";
	params.allowscriptaccess = "sameDomain";

	swfobject.embedSWF("jQueryInside.swf", "theSWF", "100", "100", "9.0.0",
				false, flashvars, params, atts);

  //]]>
</script>

</body>
</html>