/**
*
* @copyright Copyright 2001-2008 Laszlo Systems, Inc. All Rights Reserved.
* Use is subject to license terms.
*
* @access public
* @affects lztext
* @topic LFC
* @subtopic Text
*/
/**
*
This class is used for non-editable text fields (as opposed to
* inputtext. A text field can be initalized
* with text content at compile time.
*
*
*
* <canvas height="30">
* <text>Hello world!</text>
* </canvas>
*
*
* Note that certain attributes on text objects, such as opacity and rotation, only work on
* embedded fonts. They do not work on client fonts (also called platform fonts, native fonts,
* platform fonts, etc). See the Developer's Guide for details.
*
*
* for a discussion of how to include and manipulate text
* canvas.maxtextheight canvas.maxtextwidth
*
*
*
* @shortdesc The basic text display element.
* @devnote This is for regular and input text.
* @lzxname text
*
* @initarg Boolean password
* @initarg Boolean multiline
* @initarg String font
* @initarg Number fontsize
* @initarg String fontstyle
* @initarg Boolean resize
* @initarg String text
* @initarg Number maxlength: maximum number of characters allowed in this field
* default: null
* @initarg String antiAliasType (swf8 only)
* @initarg String gridFit (swf8 only)
* @initarg Number sharpness (swf8 only)
* @initarg Number thickness (swf8 only)
* @initarg String pattern: regexp describing set of characters allowed in this field
* Restrict the characters that can be entered to a pattern
* specified by a regular expression.
*
* Currently only the expression [ ]* enclosing a set of
* characters or character ranges, preceded by an optional "^", is
* supported.
*
* examples: [0-9]* , [a-zA-Z0-9]*, [^0-9]*
* default: null
*
* width and height are
* virtual properties -- they have setters and getters, but the actual
* state is stored in the text sprite. They are documented in the superclass, LzView, as well.
*
* height: The height of the text field. A Number. If unspecified,
* then the height of the text field will be set
* by default to enclose the initial text value.
*
* width: The width of the text field. A Number. If width is not explicitly
* supplied, the text field will by default be sized to fit the width of
* the initial text value.
*/
class LzText extends LzView with LzFormatter {
/** @access private
* @modifiers override
*/
static var tagname = 'text';
/** Sent whenever the text in the field changes.
* @lzxtype event
*/
var ontext = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onmaxlength = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onpattern = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onscroll = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onmaxscroll = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onhscroll = LzDeclaredEvent;
/** @lzxtype event
* @access private */
var onmaxhscroll = LzDeclaredEvent;
/**
* @access private
*/
var scroll = 0;
/**
* @access private
*/
var maxscroll = 0;
/**
* @access private
*/
var hscroll = 0;
/**
* @access private
*/
var maxhscroll = 0;
/**
* Width to use for text field if none is specified
* @access private
*/
function getDefaultWidth () {
return 0;
}
defaultattrs.pixellock = true;
/**
* If true, the lines of text are wrapped to fit within the text
* width. (The name multiline is a misnomer. Unwrapped text
* can be multiple lines if it contains a <br />
* or <p>
* element, or a line break within a <pre> element.
*
* This attribute defaults to true if width and height are
* explicitly specified.
*
* If you set multiline=true, you probably want to explicitly a
* width for the text also; if multiline=true and you do not specify
* a width, the system will pick an arbitrary width (100 pixels at
* the moment).
*
* When multiline=true, the text is automatially re-wrapped whenever
* the content is modified by calls to setText, or whenever the
* width of the text view is modified.
*
* @keywords final
* @lzxtype boolean
* @lzxdefault "false"
*/
var multiline;
/**
* If true, the width of the text field will be recomputed each time
* setText() is called, so that the text view is exactly as wide as
* the width of the widest line. Defaults to true.
*
* @lzxtype booleanLiteral
* @modifiers read-only
*/
var resize = true;
/**
* The text to display in this text field.
* @lzxtype string
*/
var text;
/** @access private */
var colorstring = "#000000"; // black
/** @access private */
function init () {
super.init.apply(this, arguments);
// [max] had to do this because text fields don't have a height until they're attached into the DOM.
// multiline resizable fields adjust their height
if (this.sizeToHeight) {
var h = this.sprite.getTextfieldHeight();
if (h > 0) {
this.setHeight(h);
}
}
}
/**
* @access private
*/
function construct ( parent, args ) {
this.password = ('password' in args && args.password) ? true : false;
this.multiline = ('multiline' in args) ? args.multiline : null;
super.construct.apply(this, arguments);
this.sizeToHeight = false;
this.fontname = ('font' in args) ? args.font : this.searchParents( "fontname" ).fontname ;
this.fontsize = ('fontsize' in args) ? args.fontsize : this.searchParents( "fontsize" ).fontsize ;
this.fontstyle = ('fontstyle' in args) ? args.fontstyle : this.searchParents( "fontstyle" ).fontstyle ;
args.font = this.fontname;
args.fontsize = this.fontsize;
args.fontstyle = this.fontstyle;
this.sprite.__initTextProperties(args);
args.font = LzNode._ignoreAttribute;
args.fontsize = LzNode._ignoreAttribute;
args.fontstyle = LzNode._ignoreAttribute;
//this.callInherited( "construct", arguments.callee , parent , args );
this.yscroll = 0;
this.xscroll = 0;
this.resize = ('resize' in args) ? (args.resize == true) : this.resize;
this.setResize(this.resize);
if ('maxlength' in args && args.maxlength != null) {
this.setMaxLength(args.maxlength);
}
this.text = (!('text' in args) || args.text == null) ? "" : args.text;
if(this.maxlength != null && this.text.length > this.maxlength){
this.text = this.text.substring(0, this.maxlength);
}
this.setMultiline( this.multiline );
this.sprite.setText( this.text );
// To compute our width:
// + if text is multiline:
// if no width is supplied, use parent width
// + if text is single line:
// if no width was supplied and there's no constraint, measure the text width:
// if empty text content was supplied, use DEFAULT_WIDTH
if (args.width == null) {
if (this.multiline) {
args.width = this.parent.width;
} else {
// if there's text content, measure its width
if (this.text != null && this.text != '' && this.text.length > 0) {
args.width = this.getTextWidth();
} else {
// Input text will have a nonzero default width, so it behaves
// like HTML input field.
args.width = this.getDefaultWidth();
}
}
} else {
this.setResize(false);
}
// To compute our height:
// + If height is supplied, use it.
// + if no height supplied:
// if single line, use font line height
// else get height from flash textobject.textHeight
//
if (!this.hassetheight) {
this.sizeToHeight = true;
} else {
this.setHeight(args.height);
}
// Default the scrollheight to the visible height.
this.scrollheight = this.height;
if ('pattern' in args && args.pattern != null) {
this.setPattern(args.pattern);
}
if (this.capabilities.advancedfonts) {
if ('antiAliasType' in args && args.antiAliasType != null) {
this.setAntiAliasType(args.antiAliasType);
} else {
this.setAntiAliasType("normal");
}
if ('gridFit' in args && args.gridFit != null) {
this.setGridFit(args.gridFit);
} else {
this.setGridFit("subpixel");
}
if ('sharpness' in args && args.sharpness != null) {
this.setSharpness(args.sharpness);
} else {
this.setSharpness(0);
}
if ('thickness' in args && args.thickness != null) {
this.setThickness(args.thickness);
} else {
this.setThickness(0);
}
if (! LzText.prototype.setters.antiAliasType) {
/**
* @lzxtype string
* @modifiers virtual
*/
// no var decl since this is a virtual field
LzText.prototype.setters.antiAliasType = "setAntiAliasType";
LzText.prototype.defaultattrs.antiAliasType = "normal";
LzText.prototype.setters.gridFit = "setGridFit";
LzText.prototype.defaultattrs.gridfit = "subpixel";
LzText.prototype.setters.sharpness = "setSharpness";
LzText.prototype.defaultattrs.sharpness = 0;
LzText.prototype.setters.thickness = "setThickness";
LzText.prototype.defaultattrs.thickness = 0;
}
}
}
/**
* Called to create the sprite object. May be overridden to use a specific
* version, e.g. LzTextSprite();
* @access private
*/
function __makeSprite(args) {
//Debug.write('__makeSprite', args);
this.sprite = new LzTextSprite(this, args);
}
/**
* Get a reference to the control mc (overridden from LzView)
* @access private
*/
function getMCRef () {
return this.sprite.getMCRef();
// return this.__LZtextclip;
}
/**
* @access private
*/
setters.text = "setText";
/**
* @access private
*/
setters.resize = "setResize";
/**
* @access private
*/
setters.multiline = -1;
/**
* @access private
*/
setters.yscroll = "setYScroll";
/**
* @access private
*/
setters.xscroll = "setXScroll";
/**
* If true, the text is selectable
*
* @lzxtype booleanLiteral
* @modifiers virtual
*/
// no var decl since this is a virtual field
setters.selectable = "setSelectable";
defaultattrs.selectable = false;
/**
* @lzxtype numberExpression
* @modifiers read-only
*/
var maxlength;
/** @access private */
setters.maxlength = "setMaxLength";
/**
* @lzxtype string
* @modifiers read-only
*/
var pattern;
/** @access private */
setters.pattern = "setPattern";
defaultattrs.clip = true;
/**
* setResize set behavior of text field width when new text is added.
* LzText only (cannot be used with LzInputText).
* @param Boolean val: if true, the textfield will recompute it's width after setText() is called
*/
function setResize ( val ){
this.sprite.setResize(val);
this.resize = val;
}
/**
* @access private
*/
function setWidth ( val ){
this.sprite.setWidth(val);
super.setWidth.apply(this, arguments);
// recalculate height
if (this.sizeToHeight) {
var h = this.sprite.getTextfieldHeight();
if (h > 0) {
this.setHeight(h);
}
}
}
/**
* @access private
*/
/*
function updateMaxLines (){
var newlin = Math.floor( this.height / ( this.font.height -1 ) );
if ( newlin != this.maxlines ){
this.maxlines = newlin;
}
}
*/
//Abstract method
//LzText.prototype.setText
/**
* Appends the string to the current text in the textfield.
* @param String t: The string to add
*/
function addText ( t ){
this.setText( this.getText() + t );
}
/**
* Clears the text field (by setting its text to the empty string)
*/
function clearText ( ){
this.setText( "" );
}
/**
* @access private
* Set the maximum number of chars a textfield can contain
*/
function setMaxLength ( val ){
if (val == null || val == '') return;
this.sprite.setMaxLength(val);
this.maxlength = val;
if (this.onmaxlength.ready) this.onmaxlength.sendEvent(val);
var t = this.getText();
if(t && t.length > this.maxlength){
this.setText (t, true);
}
}
/**
* @access private
* Set the pattern of chars a textfield can contain
*/
function setPattern ( val ){
if (val == null || val == '') return;
this.sprite.setPattern(val);
this.pattern = val;
if (this.onpattern.ready) this.onpattern.sendEvent(val);
}
/**
* Calculates the current width of the text held by the text field.
*/
function getTextWidth ( ){
return this.sprite.getTextWidth();
}
/**
* Calculates the current height of the text held by the text field.
*/
function getTextHeight ( ){
return this.sprite.getTextHeight();
//return this.__LZtextclip.textHeight;
}
/**
* @access private
*/
function applyData ( d ){
if ( null == d ){
this.clearText();
} else {
this.setText( d );
}
}
/**
* @access private
*/
function toString ( ){
return "LzText: " + this.getText();
}
if ($debug) {
/**
* @access private
*/
function _dbg_name ( ){
var id = super._dbg_name();
if (id != this.toString()) {
return id;
} else {
return Debug.stringEscape(this.getText(), true);
}
}
}
/**
* @access private
*/
function setScroll ( h ){
this.sprite.setScroll(h);
}
/**
* @access private
*/
function getScroll ( ){
return this.sprite.getScroll();
}
/**
* @access private
*/
function getMaxScroll ( ){
return this.sprite.getMaxScroll();
}
/**
* @access private
*/
function getBottomScroll ( ){
return this.sprite.getBottomScroll();
}
/**
* Set the x scroll position of the textfield.
* @param Number n: set the left edge of the textfield to offset
* n pixels
* (n is always < 0)
*/
function setXScroll ( n ){
this.sprite.setXScroll(n);
//this.onxscroll.sendEvent(??);
}
/**
* Set the y scroll position of the textfield.
* @param Number n: set the top line of the textfield to offset n pixels
* vertically (n is always < 0)
*/
function setYScroll ( n ){
this.sprite.setYScroll(n);
//this.onyscroll.sendEvent(this.yscroll);
}
/**
* @access private
*/
setters.font = "setFontName";
/**
* @access private
*/
setters.fontsize = "setFontSize";
/**
* @access private
*/
setters.fontstyle = "setFontStyle";
/**
* @access private
*/
function annotateAAimg (txt) {
if (typeof(txt) == "undefined") { return; }
if (txt.length == 0) { return };
var ntxt = "";
// search for
strings
var start = 0;
var end = 0;
var i;
// pattern to search for start of img tag
var IMGSTART = "
") {
break;
}
if (mode == WHITESPACE) {
if (c != " ") {
mode = ATTNAME;
attrname = c;
}
} else if (mode == ATTNAME) {
if ((c == " ") || (c == "=")) {
mode = WHITESPACE2;
} else {
attrname += c;
}
} else if (mode == WHITESPACE2) {
if ((c == " ") || (c == "=")) {
continue;
} else {
mode = ATTVAL;
delimiter = c;
attrval = "";
}
} else if (mode == ATTVAL) {
if (c != delimiter) {
attrval += c;
} else {
mode = WHITESPACE;
attrs[attrname] = attrval;
}
}
}
return end;
}
/**
* setText sets the text of the field to display
* @param String t: the string to which to set the text
*/
function setText ( t, force ){
// force to a string
t = '' + t;
if (force != true && t == this.text) return;
if (this.visible) this.sprite.setVisible(this.visible);
if (this.maxlength != null && t.length > this.maxlength){
t = t.substring(0, this.maxlength);
}
this.sprite.setText(t);
this.text = t;
if (this.width == 0 || (this.resize && this.multiline == false)) {
// single line resizable fields adjust their width to match the text
var w = this.getTextWidth();
// only set width if it changed
if (w != this.width) {
this.setWidth(w);
}
}
//resizable fields adjust their height
if (this.sizeToHeight) {
var h = this.sprite.getTextfieldHeight();
if (h > 0) {
this.setHeight(h);
}
}
if (this.ontext.ready) this.ontext.sendEvent(t);
}
/**
* Formatted output.
* Formats its arguments using and sets the text of the
* view to the result.
*
* @param string control: A control string where % indicates a
* subsequent argument is to be substituted
*
* @param *... args: arguments to be formatted according to the
* control string
*/
function format (control, args) {
this.setText(this.formatToString.apply(this, arguments));
}
/**
* This must be called after updating the measurement. This is done for speed.
*
* @access private
*/
function updateMaxLines (){
var newlin = Math.floor( this.height / ( this.font.height -1 ) );
if ( newlin != this.maxlines ){
this.maxlines = newlin;
}
}
/**
* @access private
*/
prototype.getTextWidth.dependencies = function ( who , self){
return [ self , "text" ];
}
/**
* @access private
*/
prototype.getTextHeight.dependencies = function ( who , self){
return [ self , "text" ];
}
/**
* @access private
*/
prototype.getMaxScroll.dependencies = function ( who , self){
return [ self , "maxscroll" ];
}
/**
* Returns the string represented in the text field
* @return: The string in the text field
*/
function getText ( ){
return this.text;
}
/**
* @access private
*/
prototype.getText.dependencies = function ( who , self){
return [ self , "text" ];
}
static var escapeChars = { '>': '>', '<': '<'};
/**
* Returns an escaped version of the string if called with no args. If called
* with a string argument, returns an escaped version of that string (escaped
* here means markup-escaped, hot http escaped.)
* @param String ts: text string to escape
*/
function escapeText( ts ){
var t = ts == null ? this.text : ts;
var i;
for ( var ec in LzText.escapeChars ){
while( t.indexOf( ec ) > -1 ){
i = t.indexOf( ec );
t = t.substring( 0 , i ) + LzText.escapeChars[ ec ] +
t.substring( i+1 );
}
}
return t;
}
/**
* Sets the selectability (with Ibeam cursor) of the text field
* @param Boolean isSel: true if the text may be selected by the user
*/
function setSelectable ( isSel ){
this.selectable = isSel;
this.sprite.setSelectable(isSel);
}
/**
* @access private
*/
function setFontName ( fname ){
this.sprite.setFontName(fname);
this.fontname = fname;
// force recompute of height if needed
this.setText( this.getText(), true);
}
/**
* @access private
*/
function setFontSize ( fsize ){
this.sprite.setFontSize(fsize);
this.fontsize = fsize;
// force recompute of height if needed
this.setText( this.getText(), true);
}
/**
* @access private
*/
function setFontStyle ( fstyle ){
this.sprite.setFontStyle(fstyle);
this.fontstyle = fstyle;
}
/**
* Sets whether or not the textfield wraps. If false, only a single line
* of text will appear and extra lines will be trucated if the text is set with
* multiple lines.
* @param Boolean ml: true if the text field should allow multiple lines
*/
function setMultiline ( ml ){
this.sprite.setMultiline(ml);
this.multiline = (ml == true);
}
/// extensions for flash6
/**
* @access private
*/
function setBorder ( onroff ){
this.sprite.setBorder(onroff);
}
/**
* @access private
* @todo should wrapping be made orthogonal to the multiline flag?
*/
function setWordWrap ( wrap ){
this.sprite.setWordWrap(wrap);
}
/**
* @access private
*/
function setEmbedFonts ( onroff ){
this.sprite.setEmbedFonts(onroff);
}
/***
* Sets what type of antialiasing the text field should use. Only works in swf8
* and higher.
* @param aliasType "normal" or "advanced"
*/
function setAntiAliasType( aliasType ){
if (this.capabilities.advancedfonts) {
if ((aliasType == "normal") || (aliasType == "advanced")) {
this.antiAliasType = aliasType;
this.sprite.setAntiAliasType(aliasType);
} else if ($debug) {
Debug.warn("antiAliasType invalid, must be 'normal' or 'advanced', but you said '" + aliasType + "'");
}
} else if ($debug) {
this.__warnCapability('text.setAntiAliasType()');
}
}
/**
* Gets the kind of antialiasing set on this text object
*/
function getAntiAliasType() {
if (this.capabilities.advancedfonts) {
return this.antiAliasType;
} else if ($debug) {
this.__warnCapability('text.getAntiAliasType()');
}
}
/***
* Sets what type of grid fitting the text field should use.
* Only works in swf8 and higher.
* @param gridFit "none", "pixel", or "subpixel"
*/
function setGridFit( gridFit ){
if (this.capabilities.advancedfonts) {
if ((gridFit == "none") || (gridFit == "pixel") || (gridFit == "subpixel")) {
this.gridFit = gridFit;
this.sprite.setGridFit(gridFit);
} else if ($debug) {
Debug.warn("gridFit invalid, must be 'none', 'pixel', or 'subpixel' but you said '" + gridFit + "'");
}
} else if ($debug) {
this.__warnCapability('text.setGridFit()');
}
}
/**
* Gets the kind of grid fitting set on this text object
*/
function getGridFit() {
if (this.capabilities.advancedfonts) {
return this.gridFit;
} else if ($debug) {
this.__warnCapability('text.getGridFit()');
}
}
/***
* Sets the sharpness for the text rendering
* Only works in swf8 and higher.
* @param sharpness -400 to 400
*/
function setSharpness( sharpness ){
if (this.capabilities.advancedfonts) {
if ((sharpness >= -400) && (sharpness <= 400)) {
this.sharpness = sharpness;
this.sprite.setSharpness(sharpness);
} else if ($debug) {
Debug.warn("sharpness out of range, must be -400 to 400");
}
} else if ($debug) {
this.__warnCapability('text.setSharpness()');
}
}
/**
* Gets the sharpness rendering property of this text object
*/
function getSharpness() {
if (this.capabilities.advancedfonts) {
return this.sharpness;
} else if ($debug) {
this.__warnCapability('text.getSharpness()');
}
}
/***
* Sets the thickness for the text rendering
* Only works in swf8 and higher.
* @param thickness -200 to 200
*/
function setThickness( thickness ){
if (this.capabilities.advancedfonts) {
if ((thickness >= -200) && (thickness <= 200)) {
this.thickness = thickness;
this.sprite.setThickness(thickness);
} else if ($debug) {
Debug.warn("thickness out of range, must be -200 to 200");
}
} else if ($debug) {
this.__warnCapability('text.setThickness()');
}
}
/**
* Gets the thickness rendering property of this text object
*/
function getThickness() {
if (this.capabilities.advancedfonts) {
return this.thickness;
} else if ($debug) {
this.__warnCapability('text.getThickness()');
}
}
/**
* @access private
*/
//TODO Remove this
/*
function __LZforceScrollAttrs () {
this.__LZtextclip.onScroller();
}
*/
/**
*
*/
function setHScroll (s){
this.sprite.setHScroll(s);
}
/**
* Positions the text selection within the text field. If this object does
* not already have the focus, this has the ancillary effect of giving it the
* focus.
* @param Number start: The beginning of the text selection, or the position
* for the text cursor if no end is given. The index is 0 based.
* @param Number end: The end of the text selection. Optional. If not given,
* then the text cursor is positioned at the start point, but no text is
* selected.
*/
function setSelection ( start , end ){
this.sprite.setSelection(start, end);
/*
var sf = targetPath( this.__LZtextclip);
if( Selection.getFocus() != sf ) {
Selection.setFocus( sf );
}
if ( typeof( end ) == 'undefined' ){
end = start;
}
Selection.setSelection( start , end );
*/
}
/**
* Returns the position of the text cursor within this object. If the text
* cursor is not inside this object, then the method returns -1.
* @return Number: The position of the text cursor within this textfield, 0
* based. If the text cursor is not in the textfield, this method returns -1.
*/
function getSelectionPosition ( ){
return this.sprite.getSelectionPosition();
/*
var sf = targetPath( this.__LZtextclip) ;
if( Selection.getFocus() != sf ) {
return -1;
}
return Selection.getBeginIndex();
*/
}
/**
* Returns the length of the text selection in within this object. If the text
* cursor is not inside this object, then the method returns -1.
* @return Number: The length of the text selection within this textfield.
* If the text cursor is not in the textfield, this method returns -1.
*/
function getSelectionSize ( ){
return this.sprite.getSelectionSize();
/*
var sf = targetPath( this.__LZtextclip);
if( Selection.getFocus() != sf ) {
return -1;
}
var siz = Selection.getEndIndex() - Selection.getBeginIndex();
return siz;
*/
}
} // End of LzText