views:

1189

answers:

3

Hi,

I am trying to find out when a link is 'hovered over' in a text area showing html text. I wonder if listening for a cursor change kind of event might be the way. I can't find anything in the docs. Has anyone any idea what event I could listen for here?

Thanks

+1  A: 

AFAIK this is not possible. You can use CSS to style the link on rollover (which is another pain unto itself) but you cannot capture the rollover as an AS event. You can capture the click of a link using the LINK event.

James Fassett
thanks. that's what I thought. Hmmm... I wonder if there is a way to listen to when the cursor changes.
Chin
I don't think you can listen to when the mouse changes (and I'm nearly certain it is a no) Here is a list of built in [mouse events](http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/MouseEvent.html) and it does not include what you are looking for.
James Fassett
+2  A: 

You can't assign listeners, but as a workaround, you could check the position of the mouse and determine when it is hovering some portion of the text... Once you determine the link's rectangle (see TextField.getCharBoundaries()) you could either create a small sprite to listen to events, or check if the rectangle contains the Point(mouseX, mouseY) on enterFrame.

Cay
+1  A: 

That's a very interesting problem. Using Cay's suggestion, I thought of a method that would return an Array of Rectangle objects, coresponding to the locations of the text. I'm using the plural because there can be multiple rectangles needed, if the text is word rapped.

function getPhraseLocation(phrase:String, field:TextField):Array {
 // initialise the return array
 var locations:Array = new Array();
 // find the first and last chars
 var firstChar = field.text.indexOf(phrase);
 var lastChar = firstChar+phrase.length;
 // determine the bounding rectangle of the first char
 var firstCharRect = field.getCharBoundaries(firstChar);
 var crtLocation:Rectangle = new Rectangle(firstCharRect.left,firstCharRect.top,firstCharRect.width,firstCharRect.height);
 // while there are chars left in the string
 var crtChar:uint = firstChar;
 while (++crtChar<lastChar)
  // if they're on the same line, expand the current rectangle
  if (field.getCharBoundaries(crtChar).y==crtLocation.y) crtLocation.width = uint(crtLocation.width)+field.getCharBoundaries(crtChar).width;
  // if they're on the next line, due to word wrapping, create a new rectangle
  else {
   locations.push(crtLocation);
   var crtCharRect = field.getCharBoundaries(crtChar);
   crtLocation = new Rectangle(crtCharRect.left,crtCharRect.top,crtCharRect.width,crtCharRect.height);
  }
 // add the last rectangle to the array
 locations.push(crtLocation);
 // return the array
 return(locations);
}

Let's assume we created the TextField like so:

var field:TextField = new TextField();
this.addChild(field);
// move the text field to some random coordinates
field.x = 50;
field.y = 50;
// set wordwrap to true, to test the multiline behaviour of our function
field.wordWrap = true;
// set a smaller width than our text
field.width = 300;
// disable selectability, I'm not sure it would work properly, anyway
field.selectable = false;
// fill the textfield with some random html text
field.htmlText = 'Lorem ipsum dolor sit amet, consectetur adipiscing <a href="http://www.stackoverflow.com"&gt;elit. Aliquam et</a> elementum lorem. Praesent vitae nunc at mi venenatis auctor.';

Now, in order to have an event listener, we must create an object and draw the rectangles over the actual text. The rectangles are drawn in 0% alpha, so they are invisible.

// create a sprite and add it to the display list
var overlay:Sprite = new Sprite();
this.addChild(overlay);
// enable mouse actions on it and make the cursor change on hover
overlay.mouseEnabled = true;
overlay.buttonMode = true;
// call the function that returns the size and position of the bounding boxes
var locationArray:Array = getPhraseLocation('elit. Aliquam et',field);
// draw each rectangle in white transparent fill
for each (var bounds:Rectangle in locationArray) {
    overlay.graphics.beginFill(0xff0000,0);
    overlay.graphics.drawRect(bounds.x+field.x-overlay.x, bounds.y+field.y-overlay.y, bounds.width, bounds.height);
    overlay.graphics.endFill();
}

Then add the event listener for MouseOver:

overlay.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
function mouseOverHandler(evt:MouseEvent):void {
    trace('mouse over key phrase');
    // do whatever else you want to do
}

Unfortunately, because we draw something over the actual text, the links become inactive. Thus, we must add event listeners for click, also:

overlay.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(evt:MouseEvent):void {
    navigateToURL(new URLRequest('http://www.stackoverflow.com'));
}

Because we previously set the buttonMode attribute to true, the mouse will change its cursor, behaving exactly as it would have been if the link in the text would have worked.

I've defined lots of variables, to keep the code easier to understand. The code can be shortened and optimized, but it should work fine just as it is, too.

It's a hell of a workaround for the simplest of tasks, but it works. Hope it's userful.

evilpenguin
Thanks - appreciate the help.
Chin
You're welcome. :)
evilpenguin