This example is for anyone who needs to use anchor tags in ActionScript TextFields. If using AIR than 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:

HTML:
  1. <b>Index</b>
  2. <a href="#sectionA"><u>Jump to Section A</u></a>
  3. <a href="#sectionB"><u>Jump to Section B</u></a>
  4. <a href="#sectionC"><u>Jump to Section C</u></a>
  5. <a href="#sectionD"><u>Jump to Section D</u></a>
  6. <a href="#sectionE"><u>Jump to Section E</u></a>
  7. <span name="sectionA"><b>Section A</b></span>
  8. <p>...</p>
  9. <p>...</p>
  10. <a href="#top">Back to Top</a>
  11. <span name="sectionB"><b>Section B</b></span>
  12. <p>...</p>
  13. <p>...</p>
  14. <a href="#top">Back to Top</a>
  15. <span name="sectionC"><b>Section C</b></span>
  16. <p>...</p>
  17. <p>...</p>
  18. <a href="#top">Back to Top</a>
  19. <span name="sectionD"><b>Section D</b></span>
  20. <p>...</p>
  21. <p>...</p>
  22. <a href="#top">Back to Top</a>
  23. <span name="sectionE"><b>Section E</b></span>
  24. <p>...</p>
  25. <p>...</p>
  26. <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:
  1. /* CSS file */
  2. a:hover {
  3.     color: #0000FF;
  4. }
  5.  
  6. a:link {
  7.     color: #555555;
  8.     text-decoration: underline;
  9. }
  10.  
  11. a:active {
  12.     color: #FF0000;
  13. }
  14.  
  15. a:visited {
  16.     color: #555555;
  17.     text-decoration: underline
  18. }

Lets start by loading in the HTML text:

Actionscript:
  1. import com.cb.util.AnchorText;
  2. import flash.text.TextField;
  3. import flash.events.TextEvent;   
  4.  
  5. private var _htmlLoader:URLLoader = new URLLoader();
  6.  
  7. private var html_url:String = "assets/test.html";
  8. private var myText:AnchorText;
  9.  
  10. private function init():void
  11. {
  12.     _htmlLoader.addEventListener(Event.COMPLETE, htmlLoadHandler);
  13.     _htmlLoader.load(new URLRequest(html_url));
  14. }
  15.  
  16. private function htmlLoadHandler(event:Event):void
  17. {
  18.     myText = new AnchorText(_htmlLoader.data, 300);
  19.     myTextComponent.addChild(myText);
  20. }

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:

Actionscript:
  1. // Replaces '#' with 'event:' to trigger actionscript events                   
  2. protected function createAnchors():void
  3. {
  4.     var regEx:RegExp = new RegExp("<a href=\"#", "ig");
  5.     _text = _text.replace(regEx, "<a href=\"event:");            
  6. }

Next we will want to add event listeners for the event and set up our dynamic text field:

Actionscript:
  1. // Constructor
  2. public function AnchorText(text:String, width:Number = 200, height:Number = 300)
  3. {
  4.     _width = width;
  5.     _height = height;
  6.     _text = text;
  7.    
  8.     // Add event dispatching to the a href tags
  9.     createAnchors();
  10.    
  11.     _dynamicText = new TextField();
  12.     _dynamicText.addEventListener(TextEvent.LINK, anchorText);
  13.     this.addChild(_dynamicText);
  14.  
  15.     _styleSheet = new StyleSheet();
  16.    
  17.     // Comment out the following three lines if you don't have an external stylesheet
  18.     _styleLoader = new URLLoader();
  19.     _styleLoader.addEventListener(Event.COMPLETE, styleLoadHandler);
  20.     _styleLoader.load(new URLRequest(css_url))
  21.    
  22.     updateFormat();  
  23. }
  24. // Set up the TextField
  25. protected function updateFormat():void
  26. {
  27.     _dynamicText.width = _width;
  28.     _dynamicText.height = _height
  29.         _dynamicText.styleSheet = _styleSheet;
  30.     _dynamicText.wordWrap = true;
  31.     _dynamicText.htmlText = _text;
  32.     _dynamicText.selectable = true; // Text MUST be selectable     
  33. }

Finally we will want to handle the mouse clicks to the events that we set up within the text string:

Actionscript:
  1. protected function anchorText(event:TextEvent):void
  2. {
  3.     // Recognize 'back to top' links
  4.     if(event.text == "top"){
  5.         _dynamicText.scrollV = 0;
  6.         return;
  7.     }
  8.    
  9.     // Set up ghost text field to match properties of the current one
  10.     var anchorText:TextField = new TextField();
  11.     anchorText.wordWrap = true;
  12.     anchorText.width = _width;
  13.     anchorText.styleSheet = _styleSheet;  // This is REQUIRED
  14.  
  15.     // Replace the name tag with a unique pattern (^#^)
  16.     var regEx:RegExp = new RegExp("<span name=\""+ event.text +"\">", "ig");
  17.     anchorText.htmlText = _text.replace(regEx, "^#^")
  18.    
  19.     // Replace newlines with '&' to keep char count consistant
  20.     regEx = new RegExp("^", "gm");
  21.     anchorText.htmlText = anchorText.htmlText.replace(regEx, "&")
  22.  
  23.     // Remove duplicate newlines
  24.     regEx = new RegExp("&&", "g");
  25.     anchorText.htmlText = anchorText.htmlText.replace(regEx, "x")
  26.    
  27.     // Find the char location of the unique pattern   
  28.     var myIndex:int = anchorText.text.indexOf("^#^") + 3;
  29.    
  30.     // Set the scroll index to the line number of the char index
  31.     var scrollIndex:int = _dynamicText.getLineIndexOfChar(myIndex) + 1;
  32.    
  33.     // Scroll to the necessary line
  34.     _dynamicText.scrollV = scrollIndex;
  35. }

Some key things to note would be:

  • 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:
http://www.kirupa.com/forum/showthread.php?t=303186

http://troyworks.com/blog/2008/03/14/flash-textfield-actionscript-hyperlink-in-as30/

Tags: , , , , , ,