Archive for April, 2010

The atadbHashManager

Tuesday, April 27th, 2010

This is the specific hash manager for the actiontad banner. It uses the onHashChangeManager for the main functionality and also does things specific to the layout of the site and the hash values. It is the final step in the marriage between the onhashchange JavaScript event and the SWFs loading of XML based on the hash value.

package
{

	import flash.display.*;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.Event;

	import com.tadSrc.tadsClasses.onHashChangeManager;
	import com.tadSrc.tadsClasses.DOMEx;
	import com.tadSrc.tadsClasses.LoadSomeXML;

	public class atadbHashManager
	{

		public var onHashDispatch:onHashChangeManager;
		public var memory:Array = [];
		public var whosGotIt:String = "server";

		public var scriptsToUse:Class = bannerScripts; /* of public static javascript in xml function vars */ 

		public function atadbHashManager(whosGotItClientOrServer:String, scripts:Class = null)
		{
			if (scripts != null) scriptsToUse = scripts;
			whosGotIt = whosGotItClientOrServer;

			if (whosGotIt == "client") {

				/* whosGotIt will be client if the correct browser config is met
				   this is determined by the server, and passed in as flashvars */

				/* A new onHashChangeManager is instantiated with deliverContent as the function
				   that will happen when the hash changes.
				   A 1000 millisecond lag time is applied to help ensure the DOM is ready. */

				onHashDispatch = new onHashChangeManager(deliverContent, 1000);

				//after 400 milliseconds firstDelivery is called
				var t:Timer = new Timer(400, 1);
				t.addEventListener(TimerEvent.TIMER_COMPLETE, firstDelivery, false, 0, true);
				t.start();

			} 

		}

		private function firstDelivery(e:TimerEvent):void {

			var firstHashLook:String =
			(DOMEx.call(scriptsToUse.getHash)+"").toString().replace(" ", "").toLowerCase();

			DOMEx.call(scriptsToUse.changeAnchors, firstHashLook, whosGotIt);
			if (firstHashLook != "") {
				deliverContent(firstHashLook);
			}

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

		}

		public function deliverContent(h:String = ""):void {

			var contentToGet:String = "welcome";
			var chash:String = h.toLowerCase();

			contentToGet = ( chash != "") ? chash : contentToGet;

			 if (DOMEx.call(scriptsToUse.innerAlready, contentToGet) == false) {
				if (memory.indexOf(contentToGet) == -1) {
					DOMEx.call(scriptsToUse.loadSayToggle);
					memory.push(contentToGet);
					LoadSomeXML.freshXMLFile("themerz/"+contentToGet+".xml", insertContent, loadError);
				} else {

					DOMEx.call(scriptsToUse.putIn, memory[memory.indexOf(contentToGet)+1]);
				}
			  }

			DOMEx.call(scriptsToUse.changeAnchors, contentToGet, whosGotIt);
			if (DOMEx.call(scriptsToUse.anyPres) == true) DOMEx.resizeMakeAbleHorizontal("pre");

		}

		private function insertContent(e:Event = null):void {

			var newContent:XML = new XML(e.target.data);
			var astring:String = newContent.thedata.toString();
			var makemine:RegExp = new RegExp("a8[a-z]{2,}8a", "i");
			//if the data is that of an example, the dagtcmpuA function determines which
			//version of the swf to place, IE or not, and colors the code.
			if (astring.match(makemine))
                          astring = DOMEx.call(dagtcmpuA(), astring, memory[memory.length-1]);

			DOMEx.call(scriptsToUse.putIn, astring);

			memory.push(astring);

			if (DOMEx.call(scriptsToUse.anyPres) == true) DOMEx.resizeMakeAbleHorizontal("pre");
		}

		private function loadError(e:Event = null):void {

			//DOMEx.call("alert", memory[memory.length-1].toString()+" not found.");
			memory.pop();
		}

	}
}

There are a good amount of JavaScript in XML variables used in this process, so I’ve put them in their own class, called bannerScripts.

package
{

	public class bannerScripts
	{

		public static var putIn:XML =
			<script>
			<![CDATA[
			function (astring) {
				document.getElementById("top").innerHTML = astring;
			}
			]]>
			</script>;

		public static var anyPres:XML =
			<script>
			<![CDATA[
			function (astring) {
				var pr = false;
				if (document.getElementsByTagName("pre").length > 0) pr = true;
				return pr;
			}
			]]>
			</script>;

		public static var loadSayToggle:XML =
			<script>
			<![CDATA[
			function () {
				var ciner = document.getElementById("top").innerHTML.toString();
				document.getElementById("top").innerHTML = "Loading..."+ciner;
			}
			]]>
			</script>;

		public static var innerAlready:XML =
			<script>
			<![CDATA[
			function (currentContentName) {
				var r = false;
				var ciner = document.getElementById("top").innerHTML.toString();
				var checkFor = "id=\""+currentContentName;
				if (ciner.indexOf(checkFor) != -1) r = true;
				return r;
			}
			]]>
			</script>;

		public static var getHash:XML =
			<script>
			<![CDATA[
			function ()
			{
					if (window.location.toString().match("#"))
					{
						var afthash = new RegExp("[\#]{1}[a-z0-9]{1,}", "i");
						var thehashword =
							window.location.toString().match(afthash).toString().
							replace("#", "").toLowerCase();
						return(thehashword);
					}
					else {return("");}
			}
			]]>
			</script>;

		public static var changeAnchors:XML =
			<script>
			<![CDATA[
			function (current, statusWho) {

				var allAs = document.getElementsByTagName("a");
				var numAs = allAs.length;
				var napa = navigator.appName+navigator.appVersion+"";
				var isie = (napa.indexOf("MSIE") != -1 || napa.indexOf("Explorer") != -1) ? true : false;
				var properBrow = ((isie == true && napa.indexOf("8.0") != -1) || isie == false) ? true : false;

				for (var i = 0; i < numAs; i++)
				{
					var curA = allAs[i];

					if (current != "") {
						if (curA.className == "ancselec" || curA.className == "ancaselec")
							curA.className = curA.className.replace("selec", "");

						if (curA.id == ""+current+"a")
							curA.className = curA.className+"selec";
					}

					if (statusWho == "client" && properBrow == true &&
								curA.href.toString().indexOf("plain/?section=") != -1) {

						   curA.href = curA.href.toString().replace("plain/?section=", "#");
					}
				}

			}
			]]>
			</script>;

	}

}

Server side setup for onhashchange support

Monday, April 26th, 2010

This code is used to determine if the browser is IE 8, FF 3.6+ or Google Chrome 4+.

If it is one of those browsers,
then the string “client” is passed to the swf via flash vars,
and the swf handles delivering content to the page with hash values.

Otherwise it is the server that will deliver the content of the site as normal, if the user does not have one of the above browsers.

$status = "theServer";
if (isset($_SERVER['HTTP_USER_AGENT'])) {

    $agent = $_SERVER['HTTP_USER_AGENT'];

    $goodBrowser = '/FireFox|MSIE|Google|Chrome|Internet[ ]{0,}Explorer/i';

    $goodVersion = '/8[\.]{0,}[0-9]{0,}|3[\.]{1}[6789]{0,}|9[\.]{1}[0-9]{0,}/';

    $gChrome = '/chrome/i';

    $gGoogle = '/google|4[\.]{1}1/i';

    if (preg_match($goodBrowser, $agent,  $agentMatch)) {

         if (preg_match($goodVersion, $agent)) { $status = "client"; }

         if (preg_match($gChrome, $agent) && preg_match($gGoogle, $agent)) { $status = "client"; }

    }

}

<!-- at the end of the page -->
params.flashvars = "from=<?php echo($status); ?>";

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);
}