<?xml version="1.0"?>
<!--
ADOBE SYSTEMS INCORPORATED
Copyright 2005-2007 Adobe Systems Incorporated
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the license agreement accompanying it.
-->
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" minWidth="220" minHeight="200" width="325" height="300">
<mx:Metadata>
[Event(name="change", type="flash.events.Event")]
[DefaultTriggerEvent("change")]
/**
* Name of the CSS Style declaration to use for the styles for the TextArea.
* By default, the TextArea uses the RichTextEditor control's inheritable styles.
*/
[Style(name="textAreaStyleName", type="String", inherit="no")]
[IconFile("RichTextEditor.png")]
[Exclude(name="alignButtons", kind="property")]
[Exclude(name="boldButton", kind="property")]
[Exclude(name="bulletButton", kind="property")]
[Exclude(name="colorPicker", kind="property")]
[Exclude(name="defaultButton", kind="property")]
[Exclude(name="fontFamilyArray", kind="property")]
[Exclude(name="fontFamilyCombo", kind="property")]
[Exclude(name="fontSizeArray", kind="property")]
[Exclude(name="fontSizeCombo", kind="property")]
[Exclude(name="icon", kind="property")]
[Exclude(name="italicButton", kind="property")]
[Exclude(name="label", kind="property")]
[Exclude(name="layout", kind="property")]
[Exclude(name="linkTextInput", kind="property")]
[Exclude(name="toolBar", kind="property")]
[Exclude(name="toolBar2", kind="property")]
[Exclude(name="underlineButton", kind="property")]
</mx:Metadata>
<mx:Array id="fontFamilyArray">
<mx:String>_sans</mx:String>
<mx:String>_serif</mx:String>
<mx:String>_typewriter</mx:String>
<mx:String>Arial</mx:String>
<mx:String>Courier</mx:String>
<mx:String>Courier New</mx:String>
<mx:String>Geneva</mx:String>
<mx:String>Georgia</mx:String>
<mx:String>Helvetica</mx:String>
<mx:String>Times New Roman</mx:String>
<mx:String>Times</mx:String>
<mx:String>Verdana</mx:String>
</mx:Array>
<mx:Array id="fontSizeArray">
<mx:String>8</mx:String>
<mx:String>9</mx:String>
<mx:String>10</mx:String>
<mx:String>11</mx:String>
<mx:String>12</mx:String>
<mx:String>14</mx:String>
<mx:String>16</mx:String>
<mx:String>18</mx:String>
<mx:String>20</mx:String>
<mx:String>22</mx:String>
<mx:String>24</mx:String>
<mx:String>26</mx:String>
<mx:String>28</mx:String>
<mx:String>36</mx:String>
<mx:String>48</mx:String>
<mx:String>72</mx:String>
</mx:Array>
<mx:Script>
<![CDATA[
import mx.controls.textClasses.TextRange;
import mx.core.mx_internal;
import mx.core.IUITextField;
import mx.core.UITextFormat;
use namespace mx_internal;
public var fontFamilyToolTip:String = "Font Family";
public var fontSizeToolTip:String = "Font Size";
public var boldToolTip:String = "Bold";
public var italicToolTip:String = "Italic";
public var underlineToolTip:String = "Underline";
public var colorPickerToolTip:String = "Color";
public var alignToolTip:String = "Align";
public var bulletToolTip:String = "Bullet";
public var linkToolTip:String = "Link";
private var linkTextCommitted:Boolean = false;
private var showControlBarChanged:Boolean = false;
private var showToolTipsChanged:Boolean = false;
private var textChanged:Boolean = false;
private var htmlTextChanged:Boolean = false;
private var previousTextFormat:TextFormat = null;
private var textFormatChanged:Boolean = false;
// -1 is used to force updation of the ToolBar styles
private var lastCaretIndex:int = -1;
private var invalidateToolBarFlag:Boolean = false;
private var firstTime:Boolean = true;
/*
public function RichTextEditor()
{
super();
}
*/
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// defaultLinkProtocol
//----------------------------------
private var _defaultLinkProtocol:String = "http://";
[Inspectable(defaultValue="http://")]
public function get defaultLinkProtocol():String
{
return _defaultLinkProtocol;
}
public function set defaultLinkProtocol(value:String):void
{
_defaultLinkProtocol = value;
if (linkTextInput)
linkTextInput.text = _defaultLinkProtocol;
}
//----------------------------------
// showControlBar
//----------------------------------
private var _showControlBar:Boolean = true;
[Inspectable(category="General", defaultValue="true")]
public function get showControlBar():Boolean
{
return _showControlBar;
}
public function set showControlBar(value:Boolean):void
{
_showControlBar = value;
showControlBarChanged = true;
invalidateProperties();
}
//----------------------------------
// showToolTips
//----------------------------------
private var _showToolTips:Boolean = false;
[Inspectable(defaultValue="false")]
public function get showToolTips():Boolean
{
return _showToolTips;
}
public function set showToolTips(value:Boolean):void
{
_showToolTips = value;
showToolTipsChanged = true;
invalidateProperties();
}
//----------------------------------
// selection
//----------------------------------
/**
* The selected text.
*/
public function get selection():TextRange
{
return new TextRange(this, true);
}
//----------------------------------
// text
//----------------------------------
private var _text:String = "";
[Bindable("valueCommit")]
[CollapseWhiteSpace]
[NonCommittingChangeEvent("change")]
[Inspectable(category="General")]
public function get text():String
{
return textArea ? textArea.text : _text;
}
public function set text(value:String):void
{
_text = value;
textChanged = true;
invalidateProperties();
}
//----------------------------------
// htmlText
//----------------------------------
private var _htmlText:String = "";
[Bindable("valueCommit")]
[CollapseWhiteSpace]
[NonCommittingChangeEvent("change")]
[Inspectable(category="General")]
public function get htmlText():String
{
return textArea ? textArea.htmlText : _htmlText;
}
public function set htmlText(value:String):void
{
_htmlText = value;
htmlTextChanged = true;
invalidateProperties();
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
override protected function commitProperties():void
{
super.commitProperties();
if (firstTime)
{
firstTime = false;
var textAreaStyleName:String = getStyle(
"textAreaStyleName");
if (textAreaStyleName)
textArea.styleName = textAreaStyleName;
textArea.getTextField().alwaysShowSelection = true;
}
if (showControlBarChanged)
{
if (_showControlBar)
{
controlBar.height = NaN;
controlBar.visible = true;
}
else
{
controlBar.height = 0;
controlBar.visible = false;
}
showControlBarChanged = false;
}
if (showToolTipsChanged)
{
if (_showToolTips)
{
fontFamilyCombo.toolTip = fontFamilyToolTip;
fontSizeCombo.toolTip = fontSizeToolTip;
boldButton.toolTip = boldToolTip;
italicButton.toolTip = italicToolTip;
underlineButton.toolTip = underlineToolTip;
colorPicker.toolTip = colorPickerToolTip;
alignButtons.toolTip = alignToolTip;
bulletButton.toolTip = bulletToolTip;
linkTextInput.toolTip = linkToolTip;
}
else
{
fontFamilyCombo.toolTip = "";
fontSizeCombo.toolTip = "";
boldButton.toolTip = "";
italicButton.toolTip = "";
underlineButton.toolTip = "";
colorPicker.toolTip = "";
alignButtons.toolTip = "";
bulletButton.toolTip = "";
linkTextInput.toolTip = "";
}
showToolTipsChanged = false;
}
if (textChanged || htmlTextChanged)
{
// Revert previously set TextFormat.
var tf:UITextFormat = IUITextField(textArea.getTextField()).getUITextFormat();
// bullet style is not exposed in flex
// hence has to be explicitly defaulted.
tf.bullet = false;
textArea.getTextField().defaultTextFormat = tf;
if (textChanged)
{
if (_text !== null)
textArea.text = _text;
textChanged = false;
}
else
{
if (_htmlText !== null)
textArea.htmlText = _htmlText;
htmlTextChanged = false;
}
}
}
override protected function measure():void
{
// Called only when explicitWidth and
// explicitHeight are set to NaN, since
// we have set width and height explicitly
// for RTE's panel.
super.measure();
measuredMinWidth = 220;
measuredWidth = 320;
measuredMinHeight = 200;
measuredHeight = 300;
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void
{
super.styleChanged(styleProp);
if (styleProp == null || styleProp == "textAreaStyleName")
{
if (textArea)
{
var textAreaStyleName:String = getStyle("textAreaStyleName");
textArea.styleName = textAreaStyleName;
}
}
if (!invalidateToolBarFlag)
{
invalidateToolBarFlag = true;
callLater(getTextStyles);
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
private function setTextStyles(type:String, value:Object = null):void
{
var tf:TextFormat;
var beginIndex:int = textArea.getTextField().selectionBeginIndex;
var endIndex:int = textArea.getTextField().selectionEndIndex;
if (beginIndex == endIndex)
{
tf = previousTextFormat;
}
else
tf = new TextFormat();
if (type == "bold" || type == "italic" || type == "underline")
{
tf[type] = value;
}
else if (type == "align" || type == "bullet")
{
if (beginIndex == endIndex)
{
tf = new TextFormat();
}
// Apply the paragraph styles to the whole paragraph instead of just
// the selected text
beginIndex = textArea.getTextField().getFirstCharInParagraph(beginIndex) - 1;
beginIndex = Math.max(0, beginIndex);
endIndex = textArea.getTextField().getFirstCharInParagraph(endIndex) +
textArea.getTextField().getParagraphLength(endIndex) - 1;
tf[type] = value;
previousTextFormat[type] = value;
if (!endIndex)
textArea.getTextField().defaultTextFormat = tf;
}
else if (type == "font")
{
tf[type] = fontFamilyCombo.text;
}
else if (type == "size")
{
var fontSize:uint = uint(fontSizeCombo.text);
if (fontSize > 0)
tf[type] = fontSize;
}
else if (type == "color")
{
tf[type] = uint(colorPicker.selectedColor);
}
else if (type == "url")
{
if (value != defaultLinkProtocol && value != "")
{
tf[type] = value;
tf["target"] = "_blank";
}
else if (tf[type] != "")
{
tf[type] = "";
tf["target"] = "";
}
}
textFormatChanged = true;
if (beginIndex == endIndex)
{
previousTextFormat = tf;
}
else
{
textArea.getTextField().setTextFormat(tf,beginIndex,endIndex);
}
dispatchEvent(new Event("change"));
var caretIndex:int = textArea.getTextField().caretIndex;
var lineIndex:int = textArea.getTextField().getLineIndexOfChar(caretIndex);
textArea.invalidateDisplayList();
textArea.validateDisplayList();
// Scroll to make the line containing the caret under viewable area
while (lineIndex >= textArea.getTextField().bottomScrollV)
{
textArea.verticalScrollPosition++;
}
callLater(textArea.setFocus);
}
private function getTextStyles():void
{
if (!textArea)
return;
var tf:TextFormat;
var beginIndex:int = textArea.getTextField().selectionBeginIndex;
var endIndex:int = textArea.getTextField().selectionEndIndex;
if (beginIndex == endIndex)
linkTextInput.enabled = false;
else
linkTextInput.enabled = true;
if (textFormatChanged)
previousTextFormat = null;
if (beginIndex == endIndex)
{
tf = textArea.getTextField().defaultTextFormat;
if (tf.url != "")
{
var carIndex:int = textArea.getTextField().caretIndex;
if (carIndex < textArea.getTextField().length)
{
var tfNext:TextFormat=textArea.getTextField().getTextFormat(carIndex, carIndex + 1);
if (!tfNext.url || tfNext.url == "")
tf.url = tf.target = "";
}
else
tf.url = tf.target = "";
}
}
else
tf = textArea.getTextField().getTextFormat(beginIndex,endIndex);
if (!previousTextFormat || previousTextFormat.font != tf.font)
setComboSelection(fontFamilyCombo, tf.font ? tf.font : "");
if (!previousTextFormat || previousTextFormat.size != tf.size)
setComboSelection(fontSizeCombo, tf.size ? String(tf.size) : "");
if (!previousTextFormat || previousTextFormat.color != tf.color)
colorPicker.selectedColor = Number(tf.color);
if (!previousTextFormat || previousTextFormat.bold != tf.bold)
boldButton.selected = tf.bold;
if (!previousTextFormat || previousTextFormat.italic != tf.italic)
italicButton.selected = tf.italic;
if (!previousTextFormat || previousTextFormat.underline != tf.underline)
underlineButton.selected = tf.underline;
if (!previousTextFormat || previousTextFormat.align != tf.align)
{
if (tf.align == "left")
alignButtons.selectedIndex = 0;
else if (tf.align == "center")
alignButtons.selectedIndex = 1;
else if (tf.align == "right")
alignButtons.selectedIndex = 2;
else if (tf.align == "justify")
alignButtons.selectedIndex = 3;
}
if (!previousTextFormat || previousTextFormat.bullet != tf.bullet)
bulletButton.selected = tf.bullet;
if (!previousTextFormat || previousTextFormat.url != tf.url)
linkTextInput.text = (tf.url == "" || tf.url == null) ? defaultLinkProtocol : tf.url;
if (textArea.getTextField().defaultTextFormat != tf)
textArea.getTextField().defaultTextFormat = tf;
previousTextFormat = tf;
textFormatChanged = false;
lastCaretIndex = textArea.getTextField().caretIndex;
invalidateToolBarFlag = false;
}
private function setComboSelection(combo:ComboBox,val:String):void
{
var length:uint = combo.dataProvider.length;
for (var i:uint = 0; i < length; i++)
{
if (combo.dataProvider.getItemAt(i).toLowerCase() == val.toLowerCase())
{
combo.selectedIndex = i;
return;
}
}
combo.selectedIndex = -1;
combo.validateNow();
combo.text = val;
}
/**
* @private
* This method is called when the user clicks on the textArea, drags
* out of it and releases the mouse button outside the TextArea.
*/
private function systemManager_mouseUpHandler(event:MouseEvent):void
{
if (lastCaretIndex != textArea.getTextField().caretIndex)
getTextStyles();
else
{
if (textArea.getTextField().selectionBeginIndex == textArea.getTextField().selectionEndIndex)
linkTextInput.enabled = false;
else
linkTextInput.enabled = true;
}
systemManager.removeEventListener(
MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);
}
]]>
</mx:Script>
<mx:TextArea id="textArea" height="100%" width="100%" minHeight="0" minWidth="0"
change="dispatchEvent(event);"
valueCommit="dispatchEvent(event);"
keyUp="getTextStyles()"
keyDown="if (textFormatChanged)
{
textArea.getTextField().defaultTextFormat=previousTextFormat;
textFormatChanged = false;
}"
mouseDown="systemManager.addEventListener(
MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);"
/>
<mx:ControlBar>
<mx:ToolBar id="toolbar" width="100%" horizontalGap="7">
<mx:ComboBox id="fontFamilyCombo" editable="true"
creationComplete="getTextStyles();lastCaretIndex = -1;"
dataProvider = "{fontFamilyArray}"
close="setTextStyles('font');"
enter="setTextStyles('font');"/>
<mx:ComboBox id="fontSizeCombo" editable="true"
paddingLeft="2" paddingRight="2"
dataProvider = "{fontSizeArray}"
close="setTextStyles('size');"
enter="setTextStyles('size');"/>
<mx:HBox id="toolBar2" horizontalGap="0">
<mx:Button id="boldButton" width="20" toggle="true"
icon="@Embed('assets/icon_style_bold.png')"
click="setTextStyles('bold', event.currentTarget.selected);" />
<mx:Button id="italicButton" width="20" toggle="true"
icon="@Embed('assets/icon_style_italic.png')"
click="setTextStyles('italic', event.currentTarget.selected);" />
<mx:Button id="underlineButton" width="20" toggle="true"
icon="@Embed('assets/icon_style_underline.png')"
click="setTextStyles('underline', event.currentTarget.selected);" />
</mx:HBox>
<mx:ColorPicker id="colorPicker" width="22" height="22"
close="setTextStyles('color');"/>
<mx:VRule height="{alignButtons.height}"/>
<mx:ToggleButtonBar id="alignButtons" buttonWidth="20"
itemClick="setTextStyles('align', ToggleButtonBar(event.currentTarget).dataProvider.getItemAt(ToggleButtonBar(event.currentTarget).selectedIndex).action); " >
<mx:dataProvider>
<mx:Array>
<mx:Object icon="@Embed('assets/icon_align_left.png')" action="left"/>
<mx:Object icon="@Embed('assets/icon_align_center.png')" action="center"/>
<mx:Object icon="@Embed('assets/icon_align_right.png')" action="right"/>
<mx:Object icon="@Embed('assets/icon_align_justify.png')" action="justify"/>
</mx:Array>
</mx:dataProvider>
</mx:ToggleButtonBar>
<mx:Button id="bulletButton" width="20" toggle="true"
icon="@Embed('assets/icon_bullet.png')"
click="setTextStyles('bullet', event.currentTarget.selected);" />
<mx:VRule height="{linkTextInput.height}"/>
<mx:TextInput id="linkTextInput" width="140"
focusOut="if (linkTextCommitted)
{ trace('already committed'); linkTextCommitted = false; }
else
{ trace('not committed'); setTextStyles('url', linkTextInput.text); linkTextInput.text=defaultLinkProtocol;}"
enter="setTextStyles('url', linkTextInput.text); linkTextInput.text = defaultLinkProtocol; linkTextCommitted = true;"/>
</mx:ToolBar>
</mx:ControlBar>
</mx:Panel>