blob: 0aedecc683d9284b933e9ee24afc12b67506d971 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package spark.components
{
import flash.events.Event;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.formats.TextLayoutFormat;
import mx.core.ScrollPolicy;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import spark.components.supportClasses.SkinnableTextBase;
import spark.events.TextOperationEvent;
use namespace mx_internal;
//--------------------------------------
// Styles
//--------------------------------------
/**
* @copy spark.components.supportClasses.GroupBase#style:symbolColor
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
[Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark")]
/**
* Indicates under what conditions the horizontal scroll bar is displayed.
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @copy spark.components.Scroller#style:horizontalScrollPolicy
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
[Style(name="horizontalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]
/**
* Indicates under what conditions the vertical scroll bar is displayed.
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @copy spark.components.Scroller#style:verticalScrollPolicy
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
[Style(name="verticalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]
//--------------------------------------
// Other metadata
//--------------------------------------
[DefaultProperty("content")]
[DefaultTriggerEvent("change")]
[IconFile("TextArea.png")]
/**
* TextArea is a text-entry control that lets users enter and edit
* multiple lines of formatted text.
*
* <p><b>The skin for the Spark theme
* uses the RichEditableText class. This means that the Spark TextArea control supports
* the Text Layout Framework (TLF) library,
* which builds on the Flash Text Engine (FTE).</b>
* In combination, these layers provide text editing with
* high-quality international typography and layout.
* The skin includes a scroller that can display horizontal and vertical scrollbars
* for scrolling through the text and supports vertical scrolling with the mouse wheel.
* The RichEditableText can be accessed as <code>textDisplay</code>
* and the Scroller as <code>scroller</code>.</p>
*
* <p><b>The skin for the mobile theme uses the StyleableStageText class.</b>
* Since StyleableStageText uses native text fields it allows for better text entry and
* manipulation experiences on mobile devices however there are some
* <a href="supportClasses/StyleableStageText.html">limitations and differences</a> that you should consider.
* Because StageText is not capable of measuring text, the TextArea must be given explicit,
* percent-based, or constraint-based <code>width</code> and <code>height</code>.
* The StyleableStageText can be accessed as <code>textDisplay</code>.
* If you wish to use the TextField-based skin, rather than the
* StageText-based skin, set the <code>skinClass</code> property to
* <code>"spark.skins.mobile.TextAreaSkin"</code>.</p>
*
* <p>You can set the text to be displayed, or get the text that the user
* has entered, using the <code>text</code> property.</p>
*
* <p>The text is formatted using CSS styles such as <code>fontFamily</code>
* and <code>fontSize</code>.</p>
*
* <p>For the Spark theme, the <code>widthInChars</code> and <code>heightInLines</code>
* properties let you specify the width and height of the TextArea
* in a way that scales with the font size or you can use the <code>typicalText</code> property.
* Note that if you use <code>typicalText</code>, the <code>widthInChars</code> and
* <code>heightInLines</code> properties are ignored.
* For all themes, you can also specify an explicit width or height in pixels,
* or use a percent width and height or constraints such as
* <code>left</code> and <code>right</code>
* or <code>top</code> and <code>bottom</code>.</p>
*
* <p>You can use the <code>maxChars</code> property to limit the number
* of character that the user can enter, and the <code>restrict</code>
* to limit which characters the user can enter.
* To use this control for password input, set the
* <code>displayAsPassword</code> property to <code>true</code>.</p>
*
* <p>For the mobile theme, the soft-keyboard-specific properties, <code>autoCapitalize</code>,
* <code>autoCorrect</code>, <code>returnKeyLabel</code> and <code>softKeyboardType</code>
* properties specify keyboard hints.
* If a soft-keyboard is present but does not support a feature represented by the
* hint, the hint is ignored.
* In mobile environments with only hardware keyboards, these hints are ignored.
* </p>
*
* <p><b>Text Area for the Spark Theme</b></p>
*
* <p>The most important differences between Spark TextArea and the
* MX TextArea control are as follows:
* <ul>
* <li>Spark TextArea offers better typography, better support
* for international languages, and better text layout.</li>
* <li>Spark TextArea has an object-oriented model of rich text,
* while the MX version does not.</li>
* <li>Spark TextArea has better support for displaying
* large amounts of text.</li>
* <li>Spark TextArea requires that fonts be embedded
* differently than the MX version.
* To learn how to use the
* <code>embedAsCFF</code> attribute when you embed a font,
* see the font documentation.</li>
* </ul></p>
*
* <p>The Spark TextArea control uses the TLF object-oriented model of rich text,
* in which text layout elements such as divisions, paragraphs, spans,
* hyperlinks, and images are represented at runtime by ActionScript
* objects. You can programmatically access and manipulate these objects.
* The central object in TLF for representing rich text is a
* TextFlow. Specify rich text for a TextArea control
* by setting its <code>textFlow</code> property to a TextFlow instance.</p>
*
* <p>If you don't need to display text that has multiple formats,
* set the TextArea <code>text</code> property to a plain text string.
* See the descriptions of the <code>text</code> and <code>textFlow</code>
* properties for information about how they interact;
* for example, you can set one and get the other.</p>
*
* <p>At compile time, you can put TLF markup tags inside
* the TextArea tag, as the following example shows:
* <pre>
* &lt;s:TextArea&gt;Hello &lt;s:span fontWeight="bold"&gt;World!&lt;/s:span&gt;&lt;/s:TextArea&gt;
* </pre>
* In this example, the MXML compiler sets the TextArea <code>content</code>
* property, causing a TextFlow object to be created from the FlowElements that you specify.</p>
*
* <p>The TextArea control does not include any user interface for changing
* the formatting of the text but contains
* APIs that you can use to programmatically format text.
* For example, you can create a
* a button that, when clicked, makes the selected text bold.</p>
*
* <p>The default text formatting is determined by CSS styles
* such as <a href="supportClasses/SkinnableTextBase.html#style:fontFamily">fontFamily</a>
* and <a href="supportClasses/SkinnableTextBase.html#style:fontSize">fontSize</a>.
* Any formatting information in the TextFlow object overrides
* the default formatting provided by the CSS styles.</p>
*
* <p>You can control many characteristics of TextArea content with styles. Here
* are a few popular ones:</p>
*
* <ul><li>Control spacing between lines with the
* <code>lineHeight</code> style.</li>
* <li>Control the spacing between paragraphs with the
* <code>paragraphSpaceBefore</code> and <code>paragraphSpaceAfter</code> styles.</li>
* <li>Align or justify text using the <code>textAlign</code> and <code>textAlignLast</code> styles.</li>
* <li>Inset text from the border of the control using the <code>paddingLeft</code>, <code>paddingTop</code>,
* <code>paddingRight</code>, and <code>paddingBottom</code> styles.</li>
* </ul>
*
* <p>By default, the text wraps at the right edge of the control.
* A vertical scrollbar automatically appears when there is more
* text than fits in the TextArea.
* If you set the <code>lineBreak</code> style to <code>explicit</code>,
* new lines start only at explicit line breaks. This has the same effect as
* if you use CR (<code>\r</code>), LF (<code>\n</code>),
* or CR+LF (<code>\r\n</code>) in <code>text</code>,
* or if you use <code>&lt;p&gt;</code> and <code>&lt;br/&gt;</code>
* in TLF markup.
* In those cases, a horizontal scrollbar automatically appears
* if any lines of text are wider than the control.</p>
*
*
* <p>The Spark TextArea
* can display left-to-right (LTR) text, such as French,
* right-to-left (RTL) text, such as Arabic, and bidirectional text,
* such as a French phrase inside of an Arabic one.
* If the predominant text direction is right-to-left,
* set the <code>direction</code> style to <code>rtl</code>.
* The <code>textAlign</code> style defaults to <code>start</code>,
* which makes the text left-aligned when <code>direction</code>
* is <code>ltr</code> and right-aligned when <code>direction</code>
* is <code>rtl</code>. To get the opposite alignment,
* set <code>textAlign</code> to <code>end</code>.</p>
*
* <p>The Spark TextArea also supports
* unlimited undo/redo within one editing session.
* An editing session starts when the control gets keyboard focus
* and ends when the control loses focus.</p>
*
* <p>To use this component in a list-based component, such as a List or DataGrid,
* create an item renderer.
* For information about creating an item renderer, see
* <a href="http://help.adobe.com/en_US/flex/using/WS4bebcd66a74275c3-fc6548e124e49b51c4-8000.html">
* Custom Spark item renderers</a>. </p>
*
* <p>For the Spark theme, the TextArea control has the following default characteristics:</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>Default size</td>
* <td>188 pixels wide by 149 pixels high</td>
* </tr>
* <tr>
* <td>Minimum size</td>
* <td>36 pixels wide and 36 pixels high</td>
* </tr>
* <tr>
* <td>Maximum size</td>
* <td>10000 pixels wide and 10000 pixels high</td>
* </tr>
* <tr>
* <td>Default skin class</td>
* <td>spark.skins.spark.TextAreaSkin</td>
* </tr>
* </table>
*
* <p>For the Mobile theme, the TextArea control has the following default characteristics:</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>Default skin class</td>
* <td>spark.skins.mobile.StageTextAreaSkin</td>
* </tr>
* </table>
*
* @mxml
*
* <p>The <code>&lt;s:TextArea&gt;</code> tag inherits all of the tag
* attributes of its superclass and adds the following tag attributes:</p>
*
* <pre>
* &lt;s:TextArea
* <strong>Properties</strong>
* heightInLines="<i>Calculated default</i>" <b>[Spark theme only]</b>
* textFlow="<i>TextFlow</i>" <b>[Spark theme only]</b>
* typicalText=null <b>[Spark theme only]</b>
* widthInChars="<i>Calculated default</i>" <b>[Spark theme only]</b>
*
* <strong>Styles</strong>
* horizontalScrollPolicy="auto" <b>[Spark theme only]</b>
* symbolColor=""
* verticalScrollPolicy="auto" <b>[Spark theme only]</b>
* /&gt;
* </pre>
*
* @see #text
* @see #textFlow
* @see spark.components.TextInput
* @see spark.components.RichText
* @see spark.components.RichEditableText
* @see spark.components.Scroller
* @see spark.components.Label
* @see spark.skins.mobile.StageTextAreaSkin
* @see spark.skins.mobile.TextAreaSkin
* @see spark.skins.spark.TextAreaSkin
*
* @includeExample examples/TextAreaExample.mxml
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public class TextArea extends SkinnableTextBase
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function TextArea()
{
super();
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var horizontalScrollPolicyChanged:Boolean = false;
/**
* @private
*/
private var verticalScrollPolicyChanged:Boolean = false;
//--------------------------------------------------------------------------
//
// Skin parts
//
//--------------------------------------------------------------------------
//----------------------------------
// scroller
//----------------------------------
[SkinPart(required="false")]
/**
* The optional Scroller in the skin,
* used to scroll the RichEditableText.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public var scroller:Scroller;
//--------------------------------------------------------------------------
//
// Overridden properties
//
//--------------------------------------------------------------------------
//----------------------------------
// suggestedFocusSkinExclusions
//----------------------------------
/**
* @private
*/
private static const focusExclusions:Array = ["scroller", "textDisplay"];
/**
* @private
*/
override public function get suggestedFocusSkinExclusions():Array
{
return focusExclusions;
}
//----------------------------------
// text
//----------------------------------
[Bindable("change")]
[Bindable("textChanged")]
// Compiler will strip leading and trailing whitespace from text string.
[CollapseWhiteSpace]
/**
* @private
*/
override public function set text(value:String):void
{
// Of 'text', 'textFlow', and 'content', the last one set wins.
super.text = value;
// Trigger bindings to textChanged.
dispatchEvent(new Event("textChanged"));
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// content
//----------------------------------
/**
* @private
* This metadata tells the MXML compiler to disable some of its default
* interpretation of the value specified for the 'content' property.
* Normally, for properties of type Object, it assumes that things
* looking like numbers are numbers and things looking like arrays
* are arrays. But <content>1</content> should generate code to set the
* content to the String "1", not the int 1, and <content>[1]</content>
* should set it to the String "[1]", not the Array [ 1 ].
* However, {...} continues to be interpreted as a databinding
* expression, and @Resource(...), @Embed(...), etc.
* as compiler directives.
* Similar metadata on TLF classes causes the same rules to apply
* within <p>, <span>, etc.
*/
[RichTextContent]
/**
* This property is intended for use in MXML at compile time;
* to get or set rich text content at runtime,
* use the <code>textFlow</code> property instead. Adobe recommends using
* <code>textFlow</code> property to get and set rich text content at runtime,
* because it is strongly typed as a TextFlow rather than as an Object.
* A TextFlow is the canonical representation
* for rich text content in the Text Layout Framework.
*
* <p>The <code>content</code> property is the default property
* for TextArea, so that you can write MXML, as the following example shows:
* <pre>
* &lt;s:TextArea&gt;Hello &lt;s:span fontWeight="bold"&gt;World&lt;/s:span&gt;&lt;/s:TextArea&gt;
* </pre>
* In this example, the String and SpanElement that you specify
* as the content are used to create a TextFlow.</p>
*
* <p>This property is typed as Object because you can set it to
* to a String, a FlowElement, or an Array of Strings and FlowElements.
* In the example above, the content is
* a 2-element array. The first array element is the String
* "Hello". The second array element is a SpanElement object with the text
* "World" in boldface.</p>
*
* <p>No matter how you specify the content, the content is converted
* to a TextFlow object. When you get the value of this property, you get
* the resulting TextFlow object.</p>
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get content():Object
{
return textFlow;
}
/**
* @private
*/
public function set content(value:Object):void
{
// Of 'text', 'textFlow', and 'content', the last one set wins.
setContent(value);
}
//----------------------------------
// heightInLines
//----------------------------------
[Inspectable(category="General", minValue="0.0")]
/**
* The default height of the control, measured in lines.
*
* <p>For the Spark theme, see
* <b>spark.components.RichEditableText.heightInLines</b></p>
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @see spark.components.RichEditableText#heightInLines
*
* @default NaN
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get heightInLines():Number
{
return getHeightInLines();
}
/**
* @private
*/
public function set heightInLines(value:Number):void
{
setHeightInLines(value);
}
//----------------------------------
// textFlow
//----------------------------------
// Note:
// The 'textFlow' property is not bindable because you can't share a
// TextFlow between two editable components, due to the way that FTE and
// TLF work.
/**
* The TextFlow representing the rich text displayed by this component.
*
* <p>For the Spark theme, see
* <b>spark.components.RichEditableText.textFlow</b></p>
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @see spark.components.RichEditableText#textFlow
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get textFlow():TextFlow
{
return getTextFlow();
}
/**
* @private
*/
public function set textFlow(value:TextFlow):void
{
// Of 'text', 'textFlow', and 'content', the last one set wins.
setTextFlow(value);
}
//----------------------------------
// widthInChars
//----------------------------------
[Inspectable(category="General", minValue="0.0")]
/**
* The default width of the control, measured in em units.
*
* <p>For the Spark theme, see
* <b>spark.components.RichEditableText.widthInChars</b></p>
*
* <p><b>For the Mobile theme, this is not supported.</b></p>
*
* @see spark.components.RichEditableText#widthInChars
*
* @default NaN
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get widthInChars():Number
{
return getWidthInChars();
}
/**
* @private
*/
public function set widthInChars(value:Number):void
{
setWidthInChars(value);
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
/**
* @private
* Pushes various TextInput properties down into the RichEditableText.
*/
override protected function commitProperties():void
{
super.commitProperties();
if (horizontalScrollPolicyChanged)
{
if (scroller)
scroller.setStyle("horizontalScrollPolicy", getStyle("horizontalScrollPolicy"));
horizontalScrollPolicyChanged = false;
}
if (verticalScrollPolicyChanged)
{
if (scroller)
scroller.setStyle("verticalScrollPolicy", getStyle("verticalScrollPolicy"));
verticalScrollPolicyChanged = false;
}
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void
{
var allStyles:Boolean = (styleProp == null || styleProp == "styleName");
super.styleChanged(styleProp);
if (allStyles || styleProp == "horizontalScrollPolicy")
{
horizontalScrollPolicyChanged = true;
invalidateProperties();
}
if (allStyles || styleProp == "verticalScrollPolicy")
{
verticalScrollPolicyChanged = true;
invalidateProperties();
}
}
/**
* @private
*/
override protected function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (instance == textDisplay)
{
// In default.css, the TextArea selector has a declaration
// for lineBreak which sets it to "toFit".
// The skin is loaded after the intial properties have been
// set so these wipe out explicit sets.
textDisplay.multiline = true;
}
// The scroller, between textDisplay and this in the chain, should not
// getFocus.
else if (instance == scroller)
{
scroller.focusEnabled = false;
// TLF does scrolling in real numbers. If the scroller doesn't
// round to ints then the sets of verticalScrollPosition and
// horizontalScrollPosition will be no-ops which is desirable.
if (scroller.horizontalScrollBar)
scroller.horizontalScrollBar.snapInterval = 0;
if (scroller.verticalScrollBar)
scroller.verticalScrollBar.snapInterval = 0;
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @copy spark.components.RichEditableText#getFormatOfRange()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function getFormatOfRange(requestedFormats:Vector.<String>=null,
anchorPosition:int=-1,
activePosition:int=-1):TextLayoutFormat
{
if (!(textDisplay is RichEditableText))
return null;
return RichEditableText(textDisplay).getFormatOfRange(
requestedFormats, anchorPosition, activePosition);
}
/**
* @copy spark.components.RichEditableText#setFormatOfRange()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function setFormatOfRange(format:TextLayoutFormat,
anchorPosition:int=-1,
activePosition:int=-1):void
{
if (!(textDisplay is RichEditableText))
return;
RichEditableText(textDisplay).setFormatOfRange(
format, anchorPosition, activePosition);
}
/**
* @copy spark.components.RichEditableText#scrollToRange()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function scrollToRange(anchorPosition:int = 0,
activePosition:int = int.MAX_VALUE):void
{
if (!textDisplay)
return;
textDisplay.scrollToRange(anchorPosition, activePosition);
}
}
}