1  /**
     2   * com.sekati.utils.TextUtils
     3   * @version 3.0.3
     4   * @author jason m horwitz | sekati.com
     5   * Copyright (C) 2007  jason m horwitz, Sekat LLC. All Rights Reserved.
     6   * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
     7   */
     8   
     9  import TextField.StyleSheet;
    10  
    11  /**
    12   * Static class wrapping various Text utilities.
    13   */
    14  class com.sekati.utils.TextUtils {
    15  
    16  	/**
    17  	 * createTextField wrapper
    18  	 * @param scope (MovieClip) target movieclip scope
    19  	 * @param instanceName (String) created TextField instance name
    20  	 * @param x (Number) x pos
    21  	 * @param y (Number) y pos
    22  	 * @param w (Number) width
    23  	 * @param xh(Number) height
    24  	 * @param props (Object) object populated with extra props to apply to TextField
    25  	 * @param fprops (Object) object populated with TextFormat properties to apply to TextField
    26  	 * @param css (String) CSS Stylesheet to apply; may be either inline css or an external stylesheet url
    27  	 * @return TextField
    28  	 * 
    29  	 * {@code Usage:
    30  	 * TextUtils.create(_root, "tf", 10, 10, 100, 20, {antiAliasType:"advanced", autoSize:true, embedFonts:false, html:true, htmlText:"hello world", multiline:true, mouseWheelEnabled:true, selectable:false, type:"dynamic", wordWrap:true}, {font:"Verdana",size:9,color:0x000000});
    31  	 * }
    32  	 */
    33  	public static function create(scope:MovieClip, instanceName:String, x:Number, y:Number, w:Number, h:Number, props:Object, fprops:Object, css:String):TextField {
    34  		var t:TextField = scope.createTextField( instanceName, scope.getNextHighestDepth( ), x, y, w, h );
    35  		for (var i in props) {
    36  			t[i] = props[i];
    37  		}
    38  		if (fprops) {
    39  			TextUtils.format( t, fprops );
    40  		}
    41  		if (css) {
    42  			TextUtils.style( t, css );
    43  		}
    44  		if (props.htmlText || props.text) {
    45  			t.htmlText = (props.htmlText) ? props.htmlText : props.text;
    46  		}
    47  		return t;
    48  	}
    49  
    50  	/**
    51  	 * TextFormat wrapper
    52  	 * @param tf (TextField) target TextField
    53  	 * @param props (Object) object populated with TextFormat props to apply to TextField
    54  	 * @return Void
    55  	 * 
    56  	 * {@code Usage:
    57  	 * TextUtils.format(tf, {font:"Verdana",size:9,color:0x000000});
    58  	 * }
    59  	 */
    60  	public static function format(tf:TextField, props:Object, css:String):Void {
    61  		var str:String = (tf.html) ? tf.htmlText : tf.text;
    62  		var f:TextFormat = new TextFormat( );
    63  		for (var i in props) {
    64  			f[i] = props[i];
    65  		}
    66  		tf.setNewTextFormat( f );
    67  		if(tf.html) {
    68  			tf.htmlText = str;
    69  		} else {
    70  			tf.text = str;
    71  		}
    72  	}
    73  
    74  	/**
    75  	 * TextField.StyleSheet wrapper
    76  	 * @param tf (TextField) target TextField
    77  	 * @param css (String) CSS Stylesheet to apply; may be either inline css or an external stylesheet url
    78  	 * @return Void
    79  	 * 
    80  	 * {@code Usage:
    81  	 * TextUtils.style(tf, "css/styles.css");
    82  	 * TextUtils.style(tf, "a:link{color:#c20b10; text-decoration:none; font-style:italic;} a:hover{color:#363636; text-decoration:underline; font-style:italic;}");
    83  	 * }
    84  	 */
    85  	public static function style(tf:TextField, css:String):Void {
    86  		var str:String = tf.htmlText;
    87  		if (css.substr( css.length - 4, 4 ).toLowerCase( ) != ".css") {
    88  			var _styles:TextField.StyleSheet = new StyleSheet( );
    89  			if (_styles.parseCSS( css )) {
    90  				tf.styleSheet = _styles;
    91  				tf.htmlText = str;
    92  			}
    93  		} else {
    94  			var _styleSheet:TextField.StyleSheet = new StyleSheet( );
    95  			_styleSheet.onLoad = function (success:Boolean):Void {
    96  				if (success) {
    97  					tf.styleSheet = _styleSheet;
    98  					tf.htmlText = str;
    99  				}
   100  			};
   101  			_styleSheet.load( css );
   102  		}
   103  	}
   104  
   105  	/**
   106  	 * empty a TextField.onSetFocus, restore to default if blank onKillFocus on input textfield
   107  	 * @param tf (TextField) target TextField
   108  	 * @return Void
   109  	 * 
   110  	 * {@code Usage:
   111  	 * tf.onSetFocus = tf.onKillFocus = function ():Void { TextUtils.focusToggle (tf); };
   112  	 * }
   113  	 */
   114  	public static function focusToggle(tf:TextField):Void {
   115  		trace( "focus toggle called" );
   116  		if (tf.defval.length) {
   117  			if (tf.text == tf.defval) {
   118  				tf.text = "";
   119  			} else if (tf.text == "") {
   120  				tf.text = tf.defval;
   121  			}
   122  		} else if (tf.text.length) {
   123  			tf.defval = tf.text;
   124  			tf.text = "";
   125  		}
   126  	}
   127  
   128  	/**
   129  	 * place cursor caret at index of text in textfield
   130  	 * @param tf (TextField) target TextField
   131  	 * @param index (Number) character number to place caret
   132  	 * @return Void
   133  	 * 
   134  	 * {@code Usage:
   135  	 * TextUtils.caret (tf, 5);
   136  	 * }
   137  	 */
   138  	public static function caret(tf:TextField, index:Number):Void {
   139  		Selection.setFocus( tf );
   140  		Selection.setSelection( index, index );
   141  	}
   142  
   143  	/**
   144  	 * select an area of text with cursor within text
   145  	 * @param tf (TextField) target TextField
   146  	 * @param sIndex (Number) start character index of selection
   147  	 * @param eIndex (Number) end character index of selection
   148  	 * @return Void
   149  	 * {@code Usage:
   150  	 * TextUtils.select (tf, 5, 10);
   151  	 * }
   152  	 */
   153  	public static function select(tf:TextField, sIndex:Number, eIndex:Number):Void {
   154  		Selection.setFocus( tf );
   155  		Selection.setSelection( sIndex, eIndex );
   156  	}
   157  
   158  	/**
   159  	 * antiAlias settings for textfield
   160  	 * @param tf (TextField) target TextField
   161  	 * @param thick (Number) set thickness of antialias [-200 to 200, default:0]
   162  	 * @param sharp (Number) set sharpness of antialias [-400 to 400, default:0]
   163  	 * @param gridFitType (Number) 0:["none"-for large fonts & anim] 1:["pixel"-for legibility of left-aligned text] 2:["subpixel"-for right-aligned or centered text] [default: 1]
   164  	 * @param isAdvanced (Boolean) type of antialias: should be true for anything <48pts [default: true]
   165  	 * @return Void
   166  	 * {@code Usage:
   167  	 * TextUtils.antiAlias (tf, 200, -200, 1, true);
   168  	 * }
   169  	 */
   170  	public static function antiAlias(tf:TextField, thick:Number, sharp:Number, gridFitType:Number, isAdvanced:Boolean):Void {
   171  		var fits:Array = [ "none", "pixel", "subpixel" ];
   172  		tf.antiAliasType = (!isAdvanced) ? "normal" : "advanced";
   173  		tf.thickness = (thick) ? thick : 0;
   174  		tf.sharpness = (sharp) ? sharp : 0;
   175  		tf.gridFitType = (gridFitType && gridFitType <= 2) ? fits[gridFitType] : fits[1];
   176  	}
   177  
   178  	/**
   179  	 * ellipse text after the defined number of lines
   180  	 * @param tf (TextField) target TextField
   181  	 * @param n (Number) number of lines of text desired
   182  	 * @param ellipseLine (Boolean) ellipse at exact end of line [true] or after the last full word [false]
   183  	 * @return Void
   184  	 */
   185  	public static function excerpt(tf:TextField, n:Number, ellipseLine:Boolean):Void {
   186  		if (tf.bottomScroll > n) {
   187  			var len:Number = tf.text.length;
   188  			for (var i:Number = 0; i < len ; i++) {
   189  				tf.scroll = tf.maxscroll;
   190  				if (tf.bottomScroll > n) {
   191  					tf.text = tf.text.slice( 0, -1 );
   192  				} else {
   193  					var e:Number = (ellipseLine) ? -3 : tf.text.lastIndexOf( " " );
   194  					tf.text = tf.text.slice( 0, e );
   195  					tf.text += "...";
   196  					break;
   197  				}
   198  			}
   199  		}
   200  	}
   201  
   202  	/**
   203  	 * chop single-line text to width, use optional ellipse
   204  	 * @param tf (TextField) target text
   205  	 * @param cutW (Number) desired text width
   206  	 * @param ellipse (Boolean) add ...
   207  	 * @param longEllipse (Boolean) add ... to end of textField (currently not working)
   208  	 * @return Void
   209  	 */
   210  	public static function chop(tf:TextField, cutW:Number, ellipse:Boolean, longEllipse:Boolean):Void {
   211  		cutW = (!longEllipse) ? cutW - 3 : cutW -= 10;
   212  		if (tf.textWidth <= cutW && !longEllipse) {
   213  			return;
   214  		}
   215  		tf._visible = false;
   216  		var str:String = tf.text;
   217  		//tf.autoSize = true;
   218  		tf.text = "W";
   219  		var ww:Number = tf.textWidth;
   220  		tf.text = "A";
   221  		var aw:Number = tf.textWidth;
   222  		var ptr:Number = Math.floor( cutW / ww );
   223  		var origLen:Number = str.length;
   224  		var checkS:String = str.substr( 0, ptr );
   225  		tf.text = checkS;
   226  		var cnt:Number;
   227  		while (tf.textWidth < cutW) {
   228  			cnt = Math.floor( (cutW - tf.textWidth) / aw );
   229  			if (cnt == 0) {
   230  				break;
   231  			}
   232  			ptr += cnt;
   233  			ptr = (ptr > origLen) ? origLen : ptr;
   234  			checkS = str.substr( 0, ptr );
   235  			tf.text = checkS;
   236  			if (origLen == ptr) {
   237  				break;
   238  			}
   239  		}
   240  		tf.text = (ellipse) ? tf.text + "..." : tf.text;
   241  		if (tf.textWidth > cutW) {
   242  			while (tf.textWidth > cutW) {
   243  				checkS = checkS.substr( 0, -1 );
   244  				tf.text = ellipse ? checkS + "..." : checkS;
   245  			}
   246  		}
   247  		if (longEllipse) {
   248  			tf._parent.tf2.text = ".";
   249  			var periodW:Number = tf._parent.tf2.textWidth;
   250  			tf._parent.tf2.text = "";
   251  			var whiteSp:Number = cutW - tf.textWidth + 8;
   252  			var i:Number = Math.floor( whiteSp / periodW );
   253  			while (i-- > 0) {
   254  				tf._parent.tf2.text += ".";
   255  			}
   256  			if (whiteSp < tf._parent.tf2.textWidth) {
   257  				while (whiteSp < tf._parent.tf2.textWidth) {
   258  					tf._parent.tf2.text = tf._parent.tf2.text.substr( 0, -1 );
   259  				}
   260  			} else if (whiteSp > tf._parent.tf2.textWidth) {
   261  				while (tf._parent.tf2.textWidth < whiteSp) {
   262  					tf._parent.tf2.text += ".";
   263  				}
   264  				tf._parent.tf2.text = tf._parent.tf2.text.substr( 0, -1 );
   265  			}
   266  		}
   267  		tf._visible = true;
   268  	}
   269  
   270  	/**
   271  	 * simple chop single-line text to width, use optional ellipse (unoptimized version of above)
   272  	 * @param tf (TextField) target text
   273  	 * @param maxW (Number) desired text width
   274  	 * @param ellipse (Boolean) add ...
   275  	 * @return Void
   276  	 */
   277  	public static function simpleChop(tf:TextField, maxW:Number, ellipse:Boolean):Void {
   278  		var dots:String = "", oht:Boolean = tf.html, cn:String = "$__chop__" + tf._name;
   279  		if (!maxW) {
   280  			maxW = tf._width;
   281  		}
   282  		if (ellipse) {
   283  			dots = "...";
   284  		}
   285  		if (tf._parent[cn]) {
   286  			tf._parent[cn].removeTextField( );
   287  		}
   288  		var chopField:TextField = tf._parent.createTextField( cn, tf._parent.getNextHighestDepth( ), -1000, -1000, 1000, 1000 );
   289  		tf.html = true, 
   290  		chopField.html = true, 
   291  		chopField.type = tf.type, 
   292  		chopField._visible = false;
   293  		chopField.setTextFormat( tf.getTextFormat( ) );
   294  		chopField.htmlText = "W";
   295  		// test character width
   296  		maxW -= chopField.textWidth;
   297  		// padding (note: the longer the string, the more padding is required)
   298  		chopField.htmlText = tf.htmlText;
   299  		var tw:Number = chopField.textWidth;
   300  		if (tw > maxW) {
   301  			var t:String = tf.htmlText;
   302  			while (tw > maxW) {
   303  				t = t.substr( 0, t.length - 1 );
   304  				chopField.htmlText = t + dots;
   305  				tw = chopField.textWidth;
   306  			}
   307  			tf.htmlText = t + dots;
   308  		}
   309  		tf.html = oht;
   310  		chopField.removeTextField( );
   311  	}
   312  
   313  	private function TextUtils() {
   314  	}
   315  }