Products
Technologies

Developer resources

Make Text Area Links Active Without Making Text Selectable

Avg. Rating 3.0

Problem

Flash/Flex requires text areas to have the selectable property set to true if you want any embedded links to be active. Sometimes this is really distracting for your users.

Solution

A custom "LinkTextArea" component which extends TextArea can manually dispatch the appropriate "link" event.

Detailed explanation

The solution is a custom "LinkTextArea" component which extends TextArea. By overriding the "set selectable" function, we can add an event listener to respond to any clicks on the TextArea. Our "onClick" handler can parse the url property (if any) of the text under the click and dispatch a "link" event.

Because we're overriding the "set selection" function, we can turn our custom handler on when selectable is set to false or off when selectable is true. That way we don't interfere with the normal function of the Text Area when selectable is set to true.

Our onClick handler:
1) Locates the character under the mouse click.
2) Defines a Text Range consisting of that character.
3) Checks the range' url property to see if it exists.
4) If so, parses the url and includes it in a flash.events.TextEvent.LINK event which we manually dispatch with a dispatchEvent call.
NOTE: When the url is an "event," Flash automatically strips out the "event:" portion of the url before dispatching the link event. To be compatible, we need to manually strip it out before dispatching our event.

Here's the code:

package com.robsheely.text
{
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import mx.core.mx_internal;
import mx.core.UITextField;
import mx.controls.TextArea;
import mx.controls.textClasses.TextRange;
import mx.events.FlexEvent;

use namespace mx_internal;

public class LinkTextArea extends TextArea
{
public function LinkTextArea()
{
super();
addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
}

protected function onCreationComplete(pEvent:FlexEvent):void
{
selectable = false;
}

// Override the electable property so we can turn our custom onclick handler
// on if selectable is set to true. If it's set to false, we remove the
// listener so the text area can handle things as usual.
override public function set selectable(pSelectable:Boolean):void
{
super.selectable = pSelectable;
if (textField)
{
textField.selectable = pSelectable;
}
else
{
// If we're attempting to set selectable before the component
// has completed its instantiation, we need to postpone
// passing the command on to the textField (which won't have
// been created yet) until instantiation has completed.
callLater(function(pSelectable:Boolean):void
{
textField.selectable = pSelectable;
}, [pSelectable]);
}
if (!pSelectable)
{
addEventListener(MouseEvent.CLICK, onClick);
}
else
{
UITextField(textField).setSelection(-1, -1);
removeEventListener(MouseEvent.CLICK, onClick);
}
}

protected function onClick(pEvent:MouseEvent):void
{
// Find the letter under our click
var index:int = textField.getCharIndexAtPoint(pEvent.localX, pEvent.localY);
if (index != -1)
{
// convert the letter to a text range so we can extract the url
var range:TextRange = new TextRange(this, false, index, index + 1);
// make sure it contains a url
if (range.url.length > 0)
{
// The normal click event strips out the 'event;' portion of the url.
// So to be consistent, let's strip it out, too.
var url:String = range.url;
if (url.substr(0, 6) == 'event:')
{
url = url.substring(6);
}
// Manually dispatch the link event with the url neatly included
dispatchEvent(new TextEvent(TextEvent.LINK, false, false, url));
}
}
}
}
}
// Copyright (c) 2008 Robert L Sheely, Inc.


LinkTextAreaSourceAndDemo.zip
[Download a zip of the source code and demo.]
Report abuse

Related recipes