Tech Tuesday: Using anchor tags in ActionScript TextFields

This example is for anyone who needs to use anchor tags in ActionScript TextFields. If you’re using AIR then the best route is to use an HTMLLoader to load in the raw HTML. If an HTMLLoader is not an option you can use this example to create a wrapper class that mimics the anchor tag functionality. Before we get started it is important to note that TextFields have a number of properties, formats, and styles available which all have an effect on the way text is rendered. This example takes advantage of a specific set of properties in order to accurately determine the line number and char location of certain strings. Variables may require some adjustments / tweaks (or may not work at all) if the TextField properties are changed.

To get started lets take a look at the HTML we plan to load in:

<b>Index</b>
<a href="#sectionA"><u>Jump to Section A</u></a>
<a href="#sectionB"><u>Jump to Section B</u></a>
<a href="#sectionC"><u>Jump to Section C</u></a>
<a href="#sectionD"><u>Jump to Section D</u></a>
<a href="#sectionE"><u>Jump to Section E</u></a>
<span name="sectionA"><b>Section A</b></span>
<p>...</p>
<p>...</p>
<a href="#top">Back to Top</a>
<span name="sectionB"><b>Section B</b></span>
<p>...</p>
<p>...</p>
<a href="#top">Back to Top</a>
<span name="sectionC"><b>Section C</b></span>
<p>...</p>
<p>...</p>
<a href="#top">Back to Top</a>
<span name="sectionD"><b>Section D</b></span>
<p>...</p>
<p>...</p>
<a href="#top">Back to Top</a>
<span name="sectionE"><b>Section E</b></span>
<p>...</p>
<p>...</p>
<a href="#top">Back to Top</a>

The content of the paragraph files has been removed to save space (you can view the source below to get a copy of the full file). Notice that the ‘a name’ tags have been replaced with ‘span name.’ This was a quick way to prevent the styling of the link tags from modifying the style of the headers. There is probably a better way to get around this but it’s not within scope of this example. Speaking of the style sheet. . . here it is:

/* CSS file */
a:hover {
    color: #0000FF;
 }
     
a:link {
   color: #555555;
   text-decoration: underline;
 }
 
a:active {
   color: #FF0000;
}
       
a:visited {
   color: #555555;
   text-decoration: underline; 
}

Lets start by loading in the HTML text:
[as]
import com.cb.util.AnchorText;
import flash.text.TextField;
import flash.events.TextEvent;

private var _htmlLoader:URLLoader = new URLLoader();

private var html_url:String = “assets/test.html”;
private var myText:AnchorText;

private function init():void
{
_htmlLoader.addEventListener(Event.COMPLETE, htmlLoadHandler);
_htmlLoader.load(new URLRequest(html_url));
}

private function htmlLoadHandler(event:Event):void
{
myText = new AnchorText(_htmlLoader.data, 300);
myTextComponent.addChild(myText);
}
[/as]

Now lets take a look at some of the key functions within the Anchor Text class. First we will want to replace the a href # tags with something ActionScript can understand:
[as]
// Replaces ‘#’ with ‘event:’ to trigger actionscript events
protected function createAnchors():void
{
var regEx:RegExp = new RegExp(“ _text = _text.replace(regEx, " }
[/as]

Next we will want to add event listeners for the event and set up our dynamic text field:
[as]
// Constructor
public function AnchorText(text:String, width:Number = 200, height:Number = 300)
{
_width = width;
_height = height;
_text = text;

// Add event dispatching to the a href tags
createAnchors();

_dynamicText = new TextField();
_dynamicText.addEventListener(TextEvent.LINK, anchorText);
this.addChild(_dynamicText);

_styleSheet = new StyleSheet();

// Comment out the following three lines if you don't have an external stylesheet
_styleLoader = new URLLoader();
_styleLoader.addEventListener(Event.COMPLETE, styleLoadHandler);
_styleLoader.load(new URLRequest(css_url));

updateFormat();
}
// Set up the TextField
protected function updateFormat():void
{
_dynamicText.width = _width;
_dynamicText.height = _height;
_dynamicText.styleSheet = _styleSheet;
_dynamicText.wordWrap = true;
_dynamicText.htmlText = _text;
_dynamicText.selectable = true; // Text MUST be selectable
}
[/as]

Finally we will want to handle the mouse clicks to the events that we set up within the text string:
[as]
protected function anchorText(event:TextEvent):void
{
// Recognize 'back to top' links
if(event.text == "top"){
_dynamicText.scrollV = 0;
return;
}

// Set up ghost text field to match properties of the current one
var anchorText:TextField = new TextField();
anchorText.wordWrap = true;
anchorText.width = _width;
anchorText.styleSheet = _styleSheet; // This is REQUIRED

// Replace the name tag with a unique pattern (^#^)
var regEx:RegExp = new RegExp("“, “ig”);
anchorText.htmlText = _text.replace(regEx, “^#^”);

// Replace newlines with ‘&’ to keep char count consistant
regEx = new RegExp(“^”, “gm”);
anchorText.htmlText = anchorText.htmlText.replace(regEx, “&”);

// Remove duplicate newlines
regEx = new RegExp(“&&”, “g”);
anchorText.htmlText = anchorText.htmlText.replace(regEx, “x”);

// Find the char location of the unique pattern
var myIndex:int = anchorText.text.indexOf(“^#^”) + 3;

// Set the scroll index to the line number of the char index
var scrollIndex:int = _dynamicText.getLineIndexOfChar(myIndex) + 1;

// Scroll to the necessary line
_dynamicText.scrollV = scrollIndex;
}
[/as]

Some key things to note:

  • The TextField MUST be selectable
  • A StyleSheet must be applied to the TextField (even if you don’t load one in)
  • This example assumes ‘^#^’ and ‘&&’ are unique sequences
  • A TextFormat can not be used along with a StyleSheet
  • There are always exception cases when dealing with RegExp and TextFields (no warranty provided)

View Sample / Source Files

Here are a few resources I found helpful along the way:
Kirupa Forum
Flash: TextField actionscript hyperlink in AS3.0

This was originally posted on blackcj.com, Chris Black’s personal blog. Chris is a Senior Developer at Sierra Bravo.

Filed under Technology

Leave a Reply