Sunday, May 31, 2009

colorizing text as you type

For a project I worked on, I needed an input TextTield that would colorize specific kinds of words as the user is typing them. For instance, if the user types "To @be or not to be, @that is the @question," I need the words starting with at-signs to turn red. And, as I said, I needed this to happen "live," as the user types. In other words, "@be" needs to turn red before the user types "or."

Here's the Regular Expression I used: /\B@[A-Za-z0-9]+/g

It starts by looking for a word boundary (\B). This is so it will match @be but not the @be in bumble@bee. More important, I don't want it to match email addresses, which have at-signs in the middle. My RegExp will only match words starting with at-signs.

Next in the RegExp, I added the literal @ and then [A-Za-z0-9]+, which will match any number of characters, as long they are letters or digits. Finally, I added the global switch (g), so that the RegExp would match all @words, not just the first one it finds.

Here's the code, followed by some notes:

var input : TextField;

input.addEventListener( Event.CHANGE, onTextChange);

function onTextChange( event : Event ) : void
        var tfSpecial : TextFormat = new TextFormat();
        var tfDefault : TextFormat = new TextFormat();
        var allText : String = input.text;
        var caretIndex : int = input.caretIndex;
        var startIndex : int = ( caretIndex - 100 < 0 ) ? 0 : caretIndex - 100;
        var localText : String = allText.substr( startIndex, caretIndex );
        var regExp     : RegExp = new RegExp( /\B@[^ ]+/g );
        var obj : Object = regExp.exec( localText );
        tfSpecial.color = 0xFF0000;
        tfSpecial.bold = true;
        tfDefault.color = 0x000000;
        tfDefault.bold = false;
        input.setTextFormat( tfDefault, allText.length-1, allText.length  );

        while( obj != null )
                input.setTextFormat( tfSpecial, obj[ "index" ],  obj[ "index" ] + String( obj ).length );
                obj = regExp.exec( allText );


All those statements that reference "carretIndex" grab a chunk of the text, starting 100 characters before the cursor position and running to the cursor position. (Unless there's less than 100 characters of text, in which case the chunk is from the beginning to the cursor.) I do this because if the text gets long, I don't want -- or need -- to check all of it. 100 characters is probably overkill, but it allows the user to type @supercalifragilisticexpialidocious if he so chooses.

In this statement...

input.setTextFormat( tfDefault, allText.length-1, allText.length );

...I make sure the text after the cursor changes back to its default black, so that non @words won't be red.

Finally, I loop through all the RegExp matches and colorizes them.

No comments:

Post a Comment