|
I was directed to Steve Zeidner's page about creating a Flash menu for Drupal today and asked if it would be possible to create an AS3 version. Turns out it is, but there are some little tweaks that need to happen, as there always are when converting to AS3.
Source Files
All of the source files for this tutorial are available at egoant.com/dev/drupalmenu/DrupalMenu.zip
My (Very Ugly) Live Sample
It isn't even plugged in to Drupal yet, but here's the sample page:
egoant.com/dev/drupalmenu
Building the FlashVars in PHP
I have adjusted Steve's code slightly so it can be used in all the locations it needs to be for Flash to recognize it.
// get primary links for flashvars
$links = menu_primary_links(1);
$flashvars = array();
$i = 0;
if ($links) {
foreach ($links as $link) {
$flashvars[$i] = $link['title'].",".url($link['href']);
$i++;
}
}
$drupalFlashVars = "menu=" . implode(",",$flashvars) . "¤t=" . url($_GET['q']);
Making Sure Flash Can See the FlashVars
First you need to be aware that the HTML embed code that is automatically generated by flash has three locations that need to be modified for FlashVars to work. The first is in the AC_FL_RunContent function in the JavaScript area:
AC_FL_RunContent(
'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0',
'width', '600',
'height', '100',
'src', 'DrupalMenu',
'quality', 'high',
'pluginspage', 'http://www.adobe.com/go/getflashplayer',
'align', 'middle',
'play', 'true',
'loop', 'true',
'scale', 'showall',
'wmode', 'window',
'devicefont', 'false',
'id', 'DrupalMenu',
'bgcolor', '#ffffff',
'name', 'DrupalMenu',
'menu', 'true',
'allowFullScreen', 'false',
'allowScriptAccess','sameDomain',
'movie', 'DrupalMenu',
'flashvars', '<?php echo $drupalFlashVars; ?>',
'salign', ''
); //end AC code
The second place is in the Object code you will want to add the following:
<param name="FlashVars" value="<?php echo $drupalFlashVars; ?>" />
And finally in the Embed code add the following:
FlashVars=<?php echo $drupalFlashVars; ?>"
Setting Up the Flash File
I don't generally keep any of my code in the .fla any more, if I can help it. So the first thing I did was create a 600x100 AS3 Flash file and set the class to DrupalMenu. Then I created the following file in the same directory as the FLA:
package
{
import flash.display.MovieClip;
import flash.display.LoaderInfo;
import flash.events.MouseEvent;
import flash.net.navigateToURL;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class DrupalMenu extends MovieClip
{
var depthCount:int = 1;
var totalWidth:int = 930;
var menuWidth:int = 0;
var yPos:int = 5;
var xPos:int = 0;
var direction:String = "horizontal";
var gap:int = 5;
var startX:Number = 0;
var startY:Number = 0;
var currentNav:String = "";
var txtFormat:TextFormat = new TextFormat();
var txtFormatActive:TextFormat = new TextFormat();
var menuArray:Array = new Array();
public function DrupalMenu():void
{
txtFormat.font = "_sans";
txtFormat.color = 0x663300;
txtFormat.size = 14;
txtFormatActive.font = "_sans";
txtFormatActive.color = 0x000000;
txtFormatActive.size = 14;
txtFormatActive.bold = true;
//Get flash vars
try {
var paramName:String;
var paramValue:String;
if (this.root.loaderInfo)
{
var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;
if (paramObj)
{
if (paramObj["current"])
{
currentNav = String(paramObj["current"]);
}
if (paramObj["menu"])
{
var navArray:Array = String(paramObj["menu"]).split(",");
for (var i:int = 0; i < navArray.length; i+=2 ) {
var menuName:String = navArray[i];
var menuLink:String = navArray[i + 1];
menuArray.push(createLink(menuName, menuLink));
}
}
}
}
} catch (error:Error) {
//Throw and error here if you like
}
//Position the menu items
var currentPos:int = 0;
for each (var menuItem:Object in menuArray)
{
if (direction == "horizontal")
{
menuItem.linkClip.x = startX + currentPos;
menuItem.linkClip.y = startY;
currentPos += menuItem.linkClip.width + gap;
}
else if (direction == "vertical")
{
menuItem.linkClip.x = startX;
menuItem.linkClip.y = startY + currentPos;
currentPos += menuItem.linkClip.height + gap;
}
}
}
private function createLink(menuTitle, menuLink):Object
{
var newLink:MovieClip = new MovieClip();
newLink.buttonMode = true;
newLink.mouseChildren = false;
newLink.addEventListener(MouseEvent.CLICK, OpenURL);
var menuText:TextField = new TextField();
menuText.text = menuTitle;
menuText.autoSize = TextFieldAutoSize.LEFT;
menuText.selectable = false;
if (currentNav == menuLink)
{
menuText.setTextFormat(txtFormatActive);
}
else
{
menuText.setTextFormat(txtFormat);
}
newLink.addChild(menuText);
this.addChild(newLink);
var linkObject:Object = new Object();
linkObject.linkClip = newLink;
linkObject.linkURL = menuLink;
return linkObject;
}
private function OpenURL(evt:MouseEvent):void
{
var clickTarget:String = evt.target.name;
var navToURL:String = GetLinkURL(clickTarget);
var targetURL:URLRequest = new URLRequest(navToURL);
navigateToURL(targetURL,"_self");
}
private function GetLinkURL(targetClip:String):String
{
var targetURL:String = "";
for each (var mItem:Object in menuArray)
{
if (mItem.linkClip.name == targetClip)
{
targetURL = mItem.linkURL;
break;
}
}
return targetURL;
}
}
}
What All That Junk Does
I have put together a very simple example to start, basically it loads the menu items, sets up their links, and makes sure the active item is a different colour. If you want fancy, it's going to take a bit more work. ;)
I will break that code down for you, to help simplify it.
First I need to load the FlashVars from the page where the clip resides. This is done using the following:
var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;
All this does is grabs the variables from the page.
Next we need to process them, all of the menu items are compressed into a single, comma delimited, variable called "menu" which is processed using this code:
if (paramObj["menu"])
{
var navArray:Array = String(paramObj["menu"]).split(",");
for (var i:int = 0; i < navArray.length; i+=2 ) {
var menuName:String = navArray[i];
var menuLink:String = navArray[i + 1];
menuArray.push(createLink(menuName, menuLink));
}
}
{/codecitiation}
Before we do that, however, we need to make sure the current navgation item is defined, so the menu items can tell if they are active:
{codecitation width="500"}if (paramObj["current"])
{
currentNav = String(paramObj["current"]);
}{/codecitiation}
You will note that each menu item above is added to a menuArray, which is built using the createLink function.
{codecitation width="500"}private function createLink(menuTitle, menuLink):Object
{
var newLink:MovieClip = new MovieClip();
newLink.buttonMode = true;
newLink.mouseChildren = false;
newLink.addEventListener(MouseEvent.CLICK, OpenURL);
var menuText:TextField = new TextField();
menuText.text = menuTitle;
menuText.autoSize = TextFieldAutoSize.LEFT;
menuText.selectable = false;
if (currentNav == menuLink)
{
menuText.setTextFormat(txtFormatActive);
}
else
{
menuText.setTextFormat(txtFormat);
}
newLink.addChild(menuText);
this.addChild(newLink);
var linkObject:Object = new Object();
linkObject.linkClip = newLink;
linkObject.linkURL = menuLink;
return linkObject;
}
The createLink function does pretty much what you would expect... Creates the menu item and it's associated link. The reason I used an Object as a holder is because it is easier to find out what object was clicked using the event handler.
Finally we have two functions, the one that opens the link when something is clicked, and the one that identifies what was actually clicked:
private function OpenURL(evt:MouseEvent):void
{
var clickTarget:String = evt.target.name;
var navToURL:String = GetLinkURL(clickTarget);
var targetURL:URLRequest = new URLRequest(navToURL);
navigateToURL(targetURL,"_self");
}
private function GetLinkURL(targetClip:String):String
{
var targetURL:String = "";
for each (var mItem:Object in menuArray)
{
if (mItem.linkClip.name == targetClip)
{
targetURL = mItem.linkURL;
break;
}
}
return targetURL;
}
|