Twitter-like syntax formatter with smart truncation

2010 January 4
tags:
by Piotr Walczyszyn

Recently I needed to format a Twitter-like input string, replacing the @UserName, #Tag and http://some.url syntax with an html a tag and adding the proper event: prefix to the href content so that it could dispatch a Flex link event (more info about link events Listening for the link event in a Flex Label control). Additionally I wanted to intelligently truncate the input string to the specified maximum length. I used RegExp for syntax parsing and also extended mx.formatters.Formatter. I guess RegExp expression might be more elegant but this way was good enough for my purposes.

Formatter code:

package net.riaspace
{
	import mx.formatters.Formatter;
 
	public class TwitterFormatter extends Formatter
	{		
 
		public var truncate:Number = NaN;
 
		protected var regExp:RegExp = /((@|#)\w+)|((ht|f)tp(s?):\/\/)(\S+)/ig;
 
		public function TwitterFormatter()
		{
			super();
		}
 
		override public function format(value:Object):String
		{
			if (value != null)
			{
				var str:String = String(value);
 
				if (!isNaN(truncate) && str.length > truncate - 3)
				{
					var index:int = lastWhiteSpaceIndex(str.substr(0, truncate - 2)); // truncate - 2 checks if after last char there is no white-space
					if (index > 0)
						str = str.substring(0, index); // truncates after last white-space
					else
						str = str.substr(0, truncate - 3); // truncates at specified truncate index -3 for ...
 
					str = str + "...";
				}
 
				return str.replace(regExp, "<u><a href='event:$&'>$&</a></u>");
			}
			return null;
		}
 
		protected function lastWhiteSpaceIndex(str:String):int
		{
			return Math.max(
				str.lastIndexOf(" "), 
				str.lastIndexOf("\n"), 
				str.lastIndexOf("\r"), 
				str.lastIndexOf("\t"));
		}
	}
}

Usage example:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="1024" minHeight="768" xmlns:riaspace="net.riaspace.*">
 
	<fx:Script>
		<![CDATA[
			import mx.controls.Alert;
			protected function txt_linkHandler(event:TextEvent):void
			{
				Alert.show("Clicked: " + event.text);
			}
		]]>
	</fx:Script>
 
	<fx:Declarations>
 
		<riaspace:TwitterFormatter id="formatter" truncate="100" />
 
		<fx:String id="twitterString">
			#Lorem @ipsum http://dolor sit amet, consectetur adipiscing elit. In vehicula mollis velit a lobortis. Vivamus quis turpis non odio aliquet mattis. Proin vel nisi in nisi condimentum ornare eget porttitor tortor. Phasellus et nulla est, sit amet cursus nunc. Maecenas sit amet nisi augue, in euismod mauris. Nulla facilisi. Curabitur hendrerit aliquam magna, facilisis pellentesque justo semper eget. Quisque eleifend nisi non risus elementum ut feugiat urna ultricies. Morbi elementum augue non velit tempus tempus hendrerit sit amet diam. Mauris eleifend odio sit amet tellus luctus pellentesque. Curabitur nec massa dui, at imperdiet purus. 
		</fx:String>
 
	</fx:Declarations>
 
	<mx:Text id="txt" link="txt_linkHandler(event)" htmlText="{formatter.format(twitterString)}" 
			 width="100%" height="100%" />
 
</s:Application>
No comments yet

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS