Archive for the ‘Flash’ Category

How to insert rich text into a static text field with JSFL

Flash Keegan Street | 18 Mar. 2010 | 3 comments

Automating the Flash authoring environment with JSFL.

I avoid repetition, I can’t stand redundancy and I get bored easily. So when I was assigned the task of developing 270 very similar Flash banners, I thought there has got to be a way to automate this. I was happy to discover that JavaScript Flash (JSFL) fit the bill perfectly.

This particular project had five different banner designs (skyscraper, rectangle, leaderboard, etc) and each design was to be published with fourteen different sets of images and four different call-to-action labels. I couldn’t load the assets dynamically because the banners had to be standalone SWF files. I couldn’t embed the assets with code because I was working with AS2. So the only way to do it was to automate the Flash authoring environment itself.

I’m going to explain one part of my approach in more detail – how I replaced the values of the text fields. Updating static text fields is easy enough with JSFL, but what about when part of that text is bold or italic? The Text.setTextAttr() method lets you apply formatting to subsets of the text, as long as you know the start index and end index of the text you want to format. Normally you don’t know those indices off hand, so I wrote a function that lets you place bold and italic HTML tags in your string to mark their location. Calling the function looks like this:

htmlToFlash("<b>G'day <i>mate</b>, this is</i> pretty <b><i>cool</i></b> hey!");

That will allow you to set the value and format of a static text field with a result like this:

Rich text in a static text field in Flash with JSFL

Here’s the function:

// This function removes the <b> and <i> tags from a string, and returns the string and an array of TextAttr objects that can be used to format the string in a static text field in Flash.
function htmlToFlash(string) {
	var replaceResult;
	var textAttrCollection = Array();

	// Replace the bold tags
	var replacedAllBolds = false;
	while (!replacedAllBolds) {
		replaceResult = replaceNextTag(string, "<b>", "</b>");
		if (replaceResult.tagStartIndex > -1) {
			// Push the attribute to the collection
			textAttrCollection.push({"attrName" : "bold", "attrValue" : true, "startIndex" : replaceResult.tagStartIndex, "endIndex" : replaceResult.tagEndIndex});
			// Update the string with the bold tag removed
			string = replaceResult.string;
		} else {
			// replaceNextTag did not replace any <b> tags this iteration so they have all been replaced
			replacedAllBolds = true;
		}
	}

	// Replace the italic tags
	var replacedAllItalics = false;
	while (!replacedAllItalics) {
		replaceResult = replaceNextTag(string, "<i>", "</i>");
		if (replaceResult.tagStartIndex > -1) {
			// Update indexes for bold tags after this italic tag
			textAttrCollection = reduceIndexesGreaterThan(replaceResult.tagStartIndex, "<i>".length, textAttrCollection);
			textAttrCollection = reduceIndexesGreaterThan(replaceResult.tagEndIndex, "</i>".length, textAttrCollection);
			// Push the attribute to the collection
			textAttrCollection.push({"attrName" : "italic", "attrValue" : true, "startIndex" : replaceResult.tagStartIndex, "endIndex" : replaceResult.tagEndIndex});
			// Update the string with the italic tag removed
			string = replaceResult.string;
		} else {
			// replaceNextTag did not replace any <i> tags this iteration so they have all been replaced
			replacedAllItalics = true;
		}
	}

	var result = {"string" : string, "textAttrCollection" : textAttrCollection};
	return result;
}

// This function removes an XML tag from a string, and returns the string and the character locations of the opening and closing tags
function replaceNextTag(string, tag, closeTag) {
	var tagStartIndex = string.indexOf(tag);
	if (tagStartIndex >- 1) {
		// Chop out the opening tag
		string = string.substring(0, tagStartIndex) + string.substring(tagStartIndex + tag.length);
		var tagEndIndex = string.indexOf(closeTag, tagStartIndex);
		// Chop out the closing tag
		string = string.substring(0, tagEndIndex) + string.substring(tagEndIndex + closeTag.length);
	}
	var result = {"string" : string, "tagStartIndex" : tagStartIndex, "tagEndIndex" : tagEndIndex};
	return result;
}

// When a tag is removed we need to adjust the character index for existing TextAttr objects which are positioned further in the string
function reduceIndexesGreaterThan(theIndex, adjustment, textAttrCollection) {
	for (var i=0; i<textAttrCollection.length; i++) {
		if (textAttrCollection[i].startIndex > theIndex) {
			textAttrCollection[i].startIndex -= adjustment;
		}
		if (textAttrCollection[i].endIndex > theIndex) {
			textAttrCollection[i].endIndex -= adjustment;
		}
	}
	return textAttrCollection;
}

And here’s how you call it:

// Define the HTML string
var htmlString = "<b>G'day <i>mate</b>, this is</i> pretty <b><i>cool</i></b> hey!";

// Convert the HTML string into a plain string and an array of TextAttr objects for formatting
var result = htmlToFlash(htmlString);

// Get the text field
var txtField = fl.getDocumentDOM().timelines[0].layers[0].frames[0].elements[0];

// Set the value of the text field
txtField.setTextString(result.string);

// Apply the TextAttr format objects to the text field
for each (var textAttr in result.textAttrCollection) {
	txtField.setTextAttr(textAttr.attrName, textAttr.attrValue, textAttr.startIndex, textAttr.endIndex);
}

Hello Bonjour

Hello Bonjour is a new tool for localising website content.

At These Days a lot of the websites we build have a Flash or Flex interface with content fed in via XML documents. That makes it really easy to deploy the same website in multiple languages. You just pass in a localised XML file and voila, you’ve got a localised site.

Until now, we have been translating those XML files manually, but we’ve just made a little tool called Hello Bonjour that makes that process easier. The tool generates an interface with a Rich Text Editor for each node in your XML document. It shows the original copy and the translated copy side-by-side for easy comparison. You can customise it for each project with your client’s official font faces and brand colours to make it easy to generate content that fits the styleguide. There’s also a Find and Replace tool so you can quickly update URLs or other text throughout the entire document.

You can test out a demo here. Sharing is caring, so here’s the source code. Feel free to use it or adapt it to meet your needs.

Hello Bonjour - content translation tool

Red5, will you be my Valentine?

I am somewhat late perhaps, with my profession of love, but last week, we launched a little Valentine’s Day campaign for our clients. We used a great open-source alternative to Flash Media Server (FMS), namely Red5. Red5 has been around for a couple of years now, but this was only the second time I actually got to work with it and I must say that its ease-of-use is simply amazing. Installing the service is pretty straightforward and once you have your server up and running, you can develop applications in a matter of minutes.

Installing the Server

You can download the Red5 server package from Google Code (current version: 0.9.1 final). Once it’s downloaded, just run the executable and it will automatically install the files and then prompt you for an IP address and a port number. When setting up the server for local testing, I just use 127.0.0.1 and 8080.

Once the installation is finished, you might want to run services.msc and check if the Red5 service is installed correctly and is running. With that done, we can open up a browser window and browse to http://127.0.0.1:8080 and you’ll see the Red5 gateway. Here you can test if Red5 is running properly and you can install some of the default applications that come with the Red5 installer. Red5 runs on Java and these applications are great for people like me, who don’t know Java and want to get right down to the good stuff. You can just install one of these basic applications (I recommend installing the oflaDemo app) and once it’s installed, your front-end application can just connect through one of these.

So how about we get to the interesting bit?

Creating your First App

Creating an app in Red5 isn’t too hard if you’re familiar with the NetConnection and NetStream classes, but you can save yourself a lot of trouble if you think your application through.

I created two classes that, in my opinion, came in quite handy:

  1. Red5Connection, the Red5Connection class is a subclass of  Flash’s NetConnection class and is pretty much just a class that handles the events that a NetConnection might throw at you.
  2. AbstractClient, just an extension of a Sprite or DisplayObject. Since we needed three entirely different clients (a broadcaster, a subscriber and a simple chat client, which displayed messages sent by the other clients), it was important to have one base class with the basic logic for all three clients.

Both of these classes are available for download here: Red5 Example files

When working with Red5, you’ll use two things often: a NetStream and a Remote SharedObject. The NetStream is used to broadcast or stream video footage. A SharedObject is used to store or retrieve data remotely. We use this to broadcast data to all connected users (could be used in a simple chat client for instance)

Here’s how you would normally use the NetStream object:

_ns = new NetStream(_nc);

// get the first camera
// set the max bandwidth used by the stream to infinite and the quality to 95 (0-100)
_cam = Camera.getCamera("0");
_cam.setQuality(0, 95);

// get the first microphone and if there is one, make sure there's no loopback nor echos
_mic = Microphone.getMicrophone(0);
if(_mic){
_mic.setUseEchoSuppression(true);
_mic.setLoopBack(false);
}

// attach microphone and camera to the netstream object
_ns.attachCamera(_cam);
_ns.attachAudio(_mic);

// publish the NetStream to Red5.
// the publish method uses two parameters, a name and a type
// the name is used to identify the netstream
// the method determines whether the netstream will be recorded, appended to an existing stream or just streamed live
// possible values are "record", "append" and "live"
_ns.publish("broadcastExample", "live");

If you wanted to stop a broadcast, you could use these bits of code:


_ns.attachCamera(null); // just removes the camera
_ns.attachAudio(null); // just removes the microphone
_ns.play(false); // stops the broadcast but leaves the NetStream intact
_ns.close(); // closes the NetStream altogether

And this is how we use the SharedObject’s send() method to send data to and from all connected clients


if (_so) _so.send("methodName", parameters);

An implementation of this code can be found in the Broadcaster and Subscriber files in the zip file I provided.
To recompile the .fla files on your computer, you will need to download De Monsterdebugger and adjust the class path settings via File > Publish Settings…

Furthermore, you will need to run Red5 locally (or adjust the RED5 constant in AbstractClient.as) and have the oflaDemo app installed in order for the files to work.

Well, that’s it for me, hopefully I was able to persuade at least some people to look into Red5.

Two Flash Player Instances Accessing the Same ExternalInterface Method

We’re here again with a quick post from a busy battlefront. We’ve been hard at work on some pretty awesome projects, a few of which we’ll discuss in more detail once they’re finished, but I wanted to take the time to post about a baffling issue we encountered working with Javascript and the ExternalInterface class in AS3.

For an oncoming Nokia campaign we’ve been working on an interactive website that relies heavily on the communication between Javascript and Flash. It involves two instances of Flash Player to interact with the same bit of Javascript. We had our two swf files report to Javascript using a rudimentary event dispatcher (pretty much just a Javascript function called dispatch, that could take one or more params, one of which was the event type)

Now, the issue we encountered was that, sporadically and presenting without any recognizable pattern, the event passed on from the second of the two Player instances, would fail. We just didn’t receive any notice that anything had happened at all.  Even more baffling was that the issue only occurred in Firefox on a Windows PC.

After banging our heads against the walls and endless debugging, we finally discovered that the problem lay in the fact that we were calling the same Javascript method from two separate instances. Once we created a separate function to handle the events for both player instances, the issue resolved itself.

If anyone has any explanation as to why this would happen, we’d love to hear it from you :)
To me, it seems that Firefox is more and more becoming an endless cesspool of eternal doom for Flash developers.

On The Beach, We Flash!

After some thorough Microsoft lovin’, I figured I would talk a bit about Flash On The Beach, and the love we feel for them. Let me just start off by saying that this was my first time at Flash On The Beach, and I’m very happy to be a part of the family!

Here’s some of my favorites:

Keith Peters
How to finish coding a game without despising it

If you’re any kind of Flash developer, it’s likely that you’ve heard about Keith Peters (@bit101http://www.bit-101.com). I hadn’t seen any of his sessions live before, so I was really excited about this one, especially once I learned that it was about game development. Because lets face it, I’m a geek and I like games. The reason I liked his session a lot however, was not so much because of the gaming aspect. He talked a lot about how to do certain things, like use a LoadManager class for your assets, or SoundManagers to handle your sounds. Things that are also useful when working on web related projects. Things that I already used, but had no idea that other people were using them too. The reason I liked Keith’s session, was that I finally got some confirmation about the methods I work with and because he made a clear, concise list of methods and best practices that can really help you with any type of project, be it a game or a web app.

Chuck Freedman & Jared Ficklin
Sound Gurus-r-us

I used to listen to music and stare at the visualizations that came with Winamp for hours on end when I was ten. I’m most definitely no music expert, but I’ve always liked sound (not music per sé… sound) and especially the idea of visualizing said sounds. And I guess that’s why I absolutely enjoyed these sessions by Chuck Freedman (@chuckstarhttp://www.getmicrophone.com) and Jared Ficklin (@jaredrawk). Not only that, but they’ve inspired me to do some experiments of my own. (more on that in another post ;) ) Chuck talked about the woes with the getMicrophone method in Actionscript, which allows you to do some really cool stuff even now, but is still lacking when it comes to using the input from the microphone for your creative purposes. Thankfully, he and a lot of other people from around the world have provided us with some temporary solutions to this problem until the good people at Adobe decide to listen up and resolve the issue. For more on these solutions and some fine examples of what -is- actually possible with a sprinkle of creativity and a shred of sound, head on over to http://www.getmicrophone.com or support the cause over at the Adobe Bug System.

Jared Ficklin (whose radiant presentation style was one of the most amazing I saw at Flash On The Beach – or anywhere else for that matter :) ) talked mostly about homebrew-style audio visualizations and the what and how of sound in general, which I particularly liked as well.

Grant Skinner
Quick as a Flash

This man needs no introduction. Grant Skinner (@gskinnerhttp://www.gskinner.com/blog) is one of those people that you just have to see once in your life and I had the privilege of  seeing him twice (count ‘em. Two times!). Once at his ‘Quick as a Flash’ session, where he gave an in-depth overview of some really great optimization techniques and then again at the 10-minute JAM Throwdown session later that day, where he showed some kick-ass sound visualizations. You can check out the slides that go with his talk at: http://gskinner.com/talks/quick/.

Joa Ebert
Leaving The Sandbox

The man coded a 3D Sound Visualizer in under ten minutes on a blank keyboard! ‘Nuff said. Check it on Vimeo (and yes, that’s me, commenting at the bottom of the page. Check out the cool custom avatar :p)

These guys, and others, like Mario Klingemann (@quasimondo),  Colin Moock and Joel Gethin Lewis (@jgl) made this into one conference I won’t easily forget. I’m already looking forward to next year’s edition! See you then Flashers!