You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by jm...@apache.org on 2014/08/26 15:17:48 UTC
[2/2] git commit: [flex-sdk] [refs/heads/develop] - FLEX-34476 Added
RichTextEditor
FLEX-34476 Added RichTextEditor
Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/d4eeb05f
Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/d4eeb05f
Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/d4eeb05f
Branch: refs/heads/develop
Commit: d4eeb05f553348f2ee246758f2e86aced7831d74
Parents: 524cdbe
Author: Justin Mclean <jm...@apache.org>
Authored: Tue Aug 26 23:16:17 2014 +1000
Committer: Justin Mclean <jm...@apache.org>
Committed: Tue Aug 26 23:16:17 2014 +1000
----------------------------------------------------------------------
.../projects/experimental/assets/tools/bold.png | Bin 0 -> 154 bytes
.../experimental/assets/tools/bullet.png | Bin 0 -> 156 bytes
.../experimental/assets/tools/center.png | Bin 0 -> 159 bytes
.../experimental/assets/tools/italic.png | Bin 0 -> 165 bytes
.../experimental/assets/tools/justify.png | Bin 0 -> 148 bytes
.../projects/experimental/assets/tools/left.png | Bin 0 -> 163 bytes
.../projects/experimental/assets/tools/link.png | Bin 0 -> 166 bytes
.../experimental/assets/tools/right.png | Bin 0 -> 160 bytes
.../experimental/assets/tools/underline.png | Bin 0 -> 167 bytes
.../src/spark/components/RichTextEditor.as | 226 ++++++++++++++++
.../richTextEditorClasses/AlignTool.mxml | 128 ++++++++++
.../richTextEditorClasses/BoldTool.mxml | 89 +++++++
.../richTextEditorClasses/BulletTool.mxml | 193 ++++++++++++++
.../richTextEditorClasses/ColorTool.mxml | 84 ++++++
.../richTextEditorClasses/FontTool.mxml | 96 +++++++
.../richTextEditorClasses/ItalicTool.mxml | 89 +++++++
.../richTextEditorClasses/LinkTool.mxml | 255 +++++++++++++++++++
.../RichTextEditorToolBar.mxml | 105 ++++++++
.../richTextEditorClasses/SizeTool.mxml | 97 +++++++
.../richTextEditorClasses/UnderlineTool.mxml | 90 +++++++
.../src/spark/skins/AlignToolSkin.mxml | 86 +++++++
21 files changed, 1538 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/bold.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/bold.png b/frameworks/projects/experimental/assets/tools/bold.png
new file mode 100755
index 0000000..04abf6d
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/bold.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/bullet.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/bullet.png b/frameworks/projects/experimental/assets/tools/bullet.png
new file mode 100755
index 0000000..aa107ba
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/bullet.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/center.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/center.png b/frameworks/projects/experimental/assets/tools/center.png
new file mode 100755
index 0000000..68428a2
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/center.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/italic.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/italic.png b/frameworks/projects/experimental/assets/tools/italic.png
new file mode 100755
index 0000000..e89f768
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/italic.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/justify.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/justify.png b/frameworks/projects/experimental/assets/tools/justify.png
new file mode 100755
index 0000000..5ea6b2a
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/justify.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/left.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/left.png b/frameworks/projects/experimental/assets/tools/left.png
new file mode 100755
index 0000000..91bfa69
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/left.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/link.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/link.png b/frameworks/projects/experimental/assets/tools/link.png
new file mode 100755
index 0000000..f771236
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/link.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/right.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/right.png b/frameworks/projects/experimental/assets/tools/right.png
new file mode 100755
index 0000000..455cc65
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/right.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/assets/tools/underline.png
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/assets/tools/underline.png b/frameworks/projects/experimental/assets/tools/underline.png
new file mode 100755
index 0000000..7d892b1
Binary files /dev/null and b/frameworks/projects/experimental/assets/tools/underline.png differ
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/RichTextEditor.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/RichTextEditor.as b/frameworks/projects/experimental/src/spark/components/RichTextEditor.as
new file mode 100644
index 0000000..1507d9e
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/RichTextEditor.as
@@ -0,0 +1,226 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 flash.utils.Dictionary;
+ import flashx.textLayout.conversion.ConversionType;
+ import flashx.textLayout.conversion.TextConverter;
+ import flashx.textLayout.elements.TextFlow;
+ import spark.components.richTextEditorClasses.RichTextEditorToolBar;
+ import spark.events.TextOperationEvent;
+
+ // for asdoc
+ [Experimental]
+ [Event(name = "change", type = "flash.events.Event")]
+ [Style(name = "borderColor", inherit = "no", type = "unit")]
+ [Style(name = "focusColor", inherit = "yes", type = "unit")]
+ public class RichTextEditor extends Group
+ {
+ private var _htmlText:String;
+ private var _htmlTextChanged:Boolean = false;
+ private var _prompt:String = "";
+ private var _stylesChanged:Dictionary = new Dictionary;
+ private var _text:String;
+ private var _textArea:TextArea;
+ private var _textFlow:TextFlow;
+
+ public function RichTextEditor()
+ {
+ super();
+ this.textFlow = new TextFlow; //Prevents a stack trace that happends when you try to access the textflow on click.
+ }
+
+ [Bindable("change")]
+ /**
+ * The htmlText property is here for convenience. It converts the textFlow to TextConverter.TEXT_FIELD_HTML_FORMAT.
+ */
+ public function get htmlText():String
+ {
+ if (_htmlTextChanged)
+ {
+ if (text == "")
+ {
+ _htmlText = "";
+ }
+ else
+ {
+ _htmlText = TextConverter.export(textFlow, TextConverter.TEXT_FIELD_HTML_FORMAT, ConversionType.STRING_TYPE) as String;
+ }
+ _htmlTextChanged = false;
+ }
+ return _htmlText;
+ }
+
+ /**
+ * The htmlText property is here for convenience. It converts the textFlow to TextConverter.TEXT_FIELD_HTML_FORMAT.
+ */
+ public function set htmlText(value:String):void
+ {
+ if (htmlText != value)
+ {
+ _htmlText = value;
+ if (textFlow)
+ {
+ textFlow = TextConverter.importToFlow(_htmlText, TextConverter.TEXT_FIELD_HTML_FORMAT);
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function get prompt():String
+ {
+ return _prompt;
+ }
+
+ /**
+ * @private
+ */
+ public function set prompt(value:String):void
+ {
+ _prompt = value;
+ if (_textArea)
+ {
+ _textArea.prompt = _prompt;
+ }
+ }
+
+ /**
+ * @private
+ */
+ public override function styleChanged(styleProp:String):void
+ {
+ super.styleChanged(styleProp);
+ _stylesChanged[styleProp] = getStyle(styleProp);
+ this.invalidateDisplayList();
+ }
+
+ [Bindable("change")]
+ /**
+ * The text in the textArea
+ */
+ public function get text():String
+ {
+ if (_textArea)
+ {
+ return _textArea.text;
+ }
+ else
+ {
+ return _text;
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function set text(value:String):void
+ {
+ _text = value;
+ if (_textArea)
+ {
+ _textArea.text = value;
+ }
+ }
+
+ [Bindable("change")]
+ /**
+ * The textFlow
+ */
+ public function get textFlow():TextFlow
+ {
+ return _textFlow;
+ }
+
+ /**
+ * @private
+ */
+ public function set textFlow(value:TextFlow):void
+ {
+ _textFlow = value;
+ if (_textArea)
+ {
+ _textArea.textFlow = value;
+ }
+ }
+
+ /**
+ * @private
+ */
+ protected override function createChildren():void
+ {
+ super.createChildren();
+ var container:VGroup = new VGroup;
+ container.percentHeight = 100;
+ container.percentWidth = 100;
+ this.addElement(container);
+
+ var toolbar:RichTextEditorToolBar = new RichTextEditorToolBar();
+ toolbar.percentWidth = 100;
+ toolbar.bottom = 6;
+ container.addElement(toolbar);
+
+ _textArea = new TextArea();
+ _textArea.percentHeight = 100;
+ _textArea.percentWidth = 100;
+ _textArea.addEventListener(TextOperationEvent.CHANGE, handleChange);
+ _textArea.prompt = prompt;
+ _textArea.textFlow = textFlow;
+ if (_htmlText)
+ {
+ textFlow = TextConverter.importToFlow(_htmlText, TextConverter.TEXT_FIELD_HTML_FORMAT);
+ }
+ else if (_text)
+ {
+ _textArea.text = _text;
+ }
+ container.addElement(_textArea);
+
+ toolbar.textArea = _textArea;
+ }
+
+ /**
+ * @private
+ */
+ protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+ {
+ super.updateDisplayList(unscaledWidth, unscaledHeight);
+ if (_textArea)
+ {
+ for (var key:String in _stylesChanged)
+ {
+ _textArea.setStyle(key, _stylesChanged[key]);
+ }
+ _stylesChanged = new Dictionary; //Clear it out
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleChange(e:Event):void
+ {
+ _htmlTextChanged = true;
+ this.dispatchEvent(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/AlignTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/AlignTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/AlignTool.mxml
new file mode 100644
index 0000000..20f9c5f
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/AlignTool.mxml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:ButtonBar width="80" arrowKeysWrapFocus="true" change="handleChange(event);" mouseFocusEnabled="false" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
+ xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flashx.textLayout.formats.TextAlign;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.collections.ArrayList;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ [Embed(source = "../../../../assets/tools/center.png")]
+ private const CENTER:Class;
+ [Embed(source = "../../../../assets/tools/justify.png")]
+ private const JUSTIFY:Class;
+ [Embed(source = "../../../../assets/tools/left.png")]
+ private const LEFT:Class;
+ [Embed(source = "../../../../assets/tools/right.png")]
+ private const RIGHT:Class;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ protected override function createChildren():void
+ {
+ super.createChildren();
+
+ var dp:ArrayList = new ArrayList();
+ dp.addItem({icon: LEFT, toolTip: "Left align text", value: TextAlign.LEFT});
+ dp.addItem({icon: CENTER, toolTip: "Left align text", value: TextAlign.CENTER});
+ dp.addItem({icon: RIGHT, toolTip: "Left align text", value: TextAlign.RIGHT});
+ dp.addItem({icon: JUSTIFY, toolTip: "Left align text", value: TextAlign.JUSTIFY});
+ this.dataProvider = dp;
+ }
+
+ /**
+ * @private
+ */
+ private function handleChange(e:Event):void
+ {
+ if (this.selectedItem)
+ {
+ var txtLayFmt:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ txtLayFmt.textAlign = this.selectedItem.value;
+ _textArea.setFormatOfRange(txtLayFmt, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+
+ switch (format.textAlign)
+ {
+ case TextAlign.LEFT:
+ this.selectedIndex = 0;
+ break;
+ case TextAlign.CENTER:
+ this.selectedIndex = 1;
+ break;
+ case TextAlign.RIGHT:
+ this.selectedIndex = 2;
+ break;
+ case TextAlign.JUSTIFY:
+ this.selectedIndex = 3;
+ break;
+ default:
+ this.selectedIndex = -1;
+ break;
+ }
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:ButtonBar>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BoldTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BoldTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BoldTool.mxml
new file mode 100644
index 0000000..8e1e89d
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BoldTool.mxml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:ToggleButton width="20" click="handleClick(event);" icon="@Embed('../../../../assets/tools/bold.png')" mouseFocusEnabled="false" toolTip="Bold text" xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flash.text.engine.FontWeight;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleClick(e:MouseEvent):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.fontWeight = (format.fontWeight == FontWeight.BOLD) ? FontWeight.NORMAL : FontWeight.BOLD;
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ if (format.fontWeight == FontWeight.BOLD)
+ {
+ this.selected = true;
+ }
+ else
+ {
+ this.selected = false;
+ }
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:ToggleButton>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BulletTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BulletTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BulletTool.mxml
new file mode 100644
index 0000000..ca93cd8
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/BulletTool.mxml
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:ToggleButton width="20" click="handleClick(event);" icon="@Embed('../../../../assets/tools/bullet.png')" mouseFocusEnabled="false" toolTip="Bullet points" xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flash.text.engine.FontWeight;
+ import flashx.textLayout.edit.IEditManager;
+ import flashx.textLayout.edit.ISelectionManager;
+ import flashx.textLayout.edit.SelectionState;
+ import flashx.textLayout.elements.FlowGroupElement;
+ import flashx.textLayout.elements.FlowLeafElement;
+ import flashx.textLayout.elements.ListElement;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function getSelectionState():SelectionState
+ {
+ if (_textArea.textFlow)
+ {
+ var selectionManager:ISelectionManager = _textArea.textFlow.interactionManager;
+ var selectionState:SelectionState = selectionManager.getSelectionState();
+ var startleaf:FlowLeafElement = _textArea.textFlow.findLeaf(selectionState.absoluteStart);
+ var endleaf:FlowLeafElement = _textArea.textFlow.findLeaf(selectionState.absoluteEnd);
+ selectionState.absoluteStart = startleaf.getAbsoluteStart();
+ selectionState.absoluteEnd = endleaf.getAbsoluteStart() + endleaf.parentRelativeEnd - endleaf.parentRelativeStart;
+ return selectionState;
+ }
+ return null;
+ }
+
+ /**
+ * @private
+ */
+ private function handleClick(e:MouseEvent):void
+ {
+ if (_textArea.textFlow && _textArea.textFlow.interactionManager is IEditManager)
+ {
+ var editManager:IEditManager = IEditManager(_textArea.textFlow.interactionManager);
+ var doCreate:Boolean = true;
+ var selectionState:SelectionState = getSelectionState();
+ var listElements:Array = _textArea.textFlow.getElementsByTypeName("list");
+ for each (var listElement:ListElement in listElements)
+ {
+ var start:int = listElement.getAbsoluteStart();
+ var end:int = listElement.getAbsoluteStart() + listElement.parentRelativeEnd - listElement.parentRelativeStart;
+ if (selectionState.absoluteStart == start && selectionState.absoluteEnd == end)
+ { //Same
+ removeList(listElement);
+ doCreate = false;
+ break;
+ }
+ else if (selectionState.absoluteStart == start && selectionState.absoluteEnd <= end)
+ { //Inside touching start
+ selectionState = new SelectionState(_textArea.textFlow, end, selectionState.absoluteEnd);
+ removeList(listElement);
+ editManager.createList(null, null, selectionState);
+ doCreate = false;
+ break;
+ }
+ else if (selectionState.absoluteStart >= start && selectionState.absoluteEnd == end)
+ { //Inside touching end
+ selectionState = new SelectionState(_textArea.textFlow, selectionState.absoluteStart, start);
+ removeList(listElement);
+ editManager.createList(null, null, selectionState);
+ doCreate = false;
+ break;
+ }
+ else if (selectionState.absoluteStart >= start && selectionState.absoluteEnd <= end)
+ { //Inside
+ var firstRange:SelectionState = new SelectionState(_textArea.textFlow, selectionState.absoluteStart, start);
+ var secondRange:SelectionState = new SelectionState(_textArea.textFlow, end, selectionState.absoluteEnd);
+ removeList(listElement);
+ editManager.createList(null, null, firstRange);
+ editManager.createList(null, null, secondRange);
+ doCreate = false;
+ break;
+ }
+ else if ((selectionState.absoluteStart >= start && selectionState.absoluteStart <= end) || (selectionState.absoluteEnd >= start && selectionState.absoluteEnd <= end))
+ { //Overlap. Include this list in the selection
+ selectionState = new SelectionState(_textArea.textFlow, Math.min(start, selectionState.absoluteStart), Math.max(end, selectionState.absoluteEnd));
+ removeList(listElement);
+ }
+ else if (selectionState.absoluteStart <= start && selectionState.absoluteEnd >= end)
+ { //surround. Remove this list since it will get added back in, only expanded.
+ removeList(listElement);
+ }
+ }
+ if (doCreate)
+ {
+ IEditManager(_textArea.textFlow.interactionManager).createList(null, null, selectionState);
+ }
+ _textArea.textFlow.interactionManager.setFocus();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ if (_textArea.textFlow)
+ {
+ var willRemoveBulletsIfClicked:Boolean = false;
+ var selectionState:SelectionState = getSelectionState();
+ var listElements:Array = _textArea.textFlow.getElementsByTypeName("list");
+ for each (var listElement:ListElement in listElements)
+ {
+ var start:int = listElement.getAbsoluteStart();
+ var end:int = listElement.getAbsoluteStart() + listElement.parentRelativeEnd - listElement.parentRelativeStart;
+ if (selectionState.absoluteStart == start && selectionState.absoluteEnd == end)
+ { //Same
+ willRemoveBulletsIfClicked = true;
+ break;
+ }
+ else if (selectionState.absoluteStart >= start && selectionState.absoluteEnd <= end)
+ { //Inside
+ willRemoveBulletsIfClicked = true;
+ break;
+ }
+ }
+ this.selected = willRemoveBulletsIfClicked;
+
+ }
+
+ }
+
+ /**
+ * @private
+ */
+ private function removeList(listElement:ListElement):void
+ {
+ var editManager:IEditManager = IEditManager(_textArea.textFlow.interactionManager);
+
+ var target:FlowGroupElement = listElement.parent;
+ var targetIndex:int = target.getChildIndex(listElement);
+ editManager.moveChildren(listElement, 0, listElement.numChildren, target, targetIndex);
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:ToggleButton>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ColorTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ColorTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ColorTool.mxml
new file mode 100644
index 0000000..86d3006
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ColorTool.mxml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<ns:ColorPicker height="21" width="20" choose="{handleChoose(event)}" mouseFocusEnabled="false" toolTip="Color text" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
+ xmlns:ns="http://flex.apache.org/experimental/ns" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import mx.events.FlexEvent;
+
+ import spark.components.TextArea;
+ import spark.events.ColorChangeEvent;
+ import spark.events.TextOperationEvent;
+
+ import flashx.textLayout.formats.TextLayoutFormat;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleChoose(e:ColorChangeEvent):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.color = e.color
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ this.selectedColor = format.color;
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</ns:ColorPicker>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/FontTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/FontTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/FontTool.mxml
new file mode 100644
index 0000000..f0eba89
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/FontTool.mxml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:DropDownList width="100%" change="callLater(handleChange, [event]);" dataProvider="{null}" maxWidth="120" minWidth="80" mouseFocusEnabled="false" xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.collections.ArrayList;
+ import mx.collections.IList;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private const _defaultDataProvider:ArrayList = new ArrayList(["_sans", "_serif", "_typewriter", "Arial", "Calibri", "Courier", "Courier New", "Geneva,Georgia", "Helvetica", "Times New Roman", "Times", "Trebuchet MS", "Verdana"]);
+ private var _textArea:TextArea;
+
+ public override function set dataProvider(value:IList):void
+ {
+ if (value == null)
+ {
+ super.dataProvider = _defaultDataProvider;
+ }
+ else
+ {
+ super.dataProvider = value;
+ }
+ }
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleChange(e:Event):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.fontFamily = this.selectedItem;
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ this.selectedItem = format.fontFamily;
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:DropDownList>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ItalicTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ItalicTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ItalicTool.mxml
new file mode 100644
index 0000000..9c54159
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/ItalicTool.mxml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:ToggleButton width="20" click="handleClick(event);" icon="@Embed('../../../../assets/tools/italic.png')" mouseFocusEnabled="false" toolTip="Italic text" xmlns:fx="http://ns.adobe.com/mxml/2009"
+ xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flash.text.engine.FontPosture;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleClick(e:MouseEvent):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.fontStyle = (format.fontStyle == FontPosture.ITALIC) ? FontPosture.NORMAL : FontPosture.ITALIC;
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ if (format.fontStyle == FontPosture.ITALIC)
+ {
+ this.selected = true;
+ }
+ else
+ {
+ this.selected = false;
+ }
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:ToggleButton>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/LinkTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/LinkTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/LinkTool.mxml
new file mode 100644
index 0000000..49d9f04
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/LinkTool.mxml
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:TextInput width="100%" text="" enabled="false" enter="apply(event)" keyDown="handleLinkKeydown(event)" minWidth="100" mouseFocusChange="apply(event)" mouseFocusEnabled="false"
+ toolTip="Hyperlink text" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Metadata>
+ [Event(name="linkSelectedChange", type="flash.events.Event")]
+ </fx:Metadata>
+ <fx:Script>
+ <![CDATA[
+ import flashx.textLayout.edit.ElementRange;
+ import flashx.textLayout.edit.IEditManager;
+ import flashx.textLayout.edit.SelectionState;
+ import flashx.textLayout.elements.LinkElement;
+ import flashx.textLayout.elements.ParagraphElement;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+
+ private var _linkSelected:Boolean = false;
+
+ private var _textArea:TextArea;
+ private var _urlRegExpression:RegExp = new RegExp("^(https?://(www\\.)?|www\\.)[-._~:/?#\\[\\]@!$&'()*+,;=a-z0-9]+$", 'i');
+ private const defaultLinkText:String = "http://";
+ private var lastRange:ElementRange;
+ private var _linkEl:LinkElement
+
+ [Bindable("linkSelectedChange")]
+ public function get linkSelected():Boolean
+ {
+ return _linkSelected;
+ }
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ _textArea.removeEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ _textArea.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ * Apply the link to the selected text
+ */
+ private function apply(e:Event = null):void
+ {
+ var urlText:String = this.text == defaultLinkText ? '' : this.text;
+ applyLink(urlText, "_blank", true);
+ //Set focus to textFlow
+ textArea.textFlow.interactionManager.setFocus();
+ }
+
+ /**
+ * @private
+ * Actually apply the link to the selection. Repair the formating in the process.
+ */
+ private function applyLink(href:String, target:String = null, extendToLinkBoundary:Boolean = false, operationState:SelectionState = null):void
+ {
+ if (textArea && textArea.textFlow && textArea.textFlow.interactionManager is IEditManager)
+ {
+ //Get the current format
+ var txtLayFmt:TextLayoutFormat = textArea.textFlow.interactionManager.getCommonCharacterFormat();
+ //Set the link
+ var operationState:SelectionState = null;
+ if (_linkEl != null)
+ {
+ operationState = new SelectionState(textArea.textFlow, _linkEl.getAbsoluteStart(), _linkEl.getAbsoluteStart() + _linkEl.textLength);
+ }
+ var linkElement:LinkElement = IEditManager(textArea.textFlow.interactionManager).applyLink(href, target, extendToLinkBoundary, operationState);
+ //Fix the formatting
+ if(linkElement)
+ {
+ IEditManager(textArea.textFlow.interactionManager).clearFormatOnElement(linkElement.getChildAt(0), txtLayFmt);
+ }
+ var selectionEnd:int = Math.max(textArea.selectionActivePosition, textArea.selectionAnchorPosition);
+ textArea.selectRange(selectionEnd, selectionEnd);
+ IEditManager(textArea.textFlow.interactionManager).applyLeafFormat(txtLayFmt);
+ }
+ }
+
+ /**
+ * @private
+ * Automatically add a link if the previous text looks like a link
+ */
+ private function checkLinks():void
+ {
+ var position:int = _textArea.selectionActivePosition;
+ //Find the firt non-whitespace character
+ while (position > 0)
+ {
+ if (!isWhitespace(_textArea.textFlow.getCharCodeAtPosition(position)))
+ {
+ break;
+ }
+ position--;
+ }
+ //Find the next whitespace character
+ while (position > 0)
+ {
+ if (isWhitespace(_textArea.textFlow.getCharCodeAtPosition(position)))
+ {
+ position++; //Back up one character
+ break;
+ }
+ position--;
+ }
+ var testText:String = _textArea.textFlow.getText(position, _textArea.selectionActivePosition);
+ var result:Array = testText.match(_urlRegExpression);
+ if (result != null && result.length > 0)
+ {
+ if (_textArea.textFlow.interactionManager is IEditManager)
+ {
+ var selectionState:SelectionState = new SelectionState(_textArea.textFlow, position, _textArea.selectionActivePosition);
+ if (testText.substr(0, 3) == "www")
+ {
+ testText = "http://" + testText; //Add a missing 'http://' if needed
+ }
+ applyLink(testText, "_blank", true, selectionState);
+ _textArea.setFocus();
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleKeyDown(e:KeyboardEvent):void
+ {
+ if (e.keyCode == Keyboard.ENTER || e.keyCode == Keyboard.SPACE || e.keyCode == Keyboard.TAB)
+ {
+ checkLinks();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleLinkKeydown(e:KeyboardEvent):void
+ {
+ e.stopImmediatePropagation();
+ if (e.keyCode == Keyboard.ENTER)
+ {
+ _textArea.setFocus();
+ }
+ }
+
+ /**
+ * @private
+ * Update the text display based on the selected range
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var selectionState:SelectionState = _textArea.textFlow.interactionManager.getSelectionState();
+ if (selectionState.absoluteStart != -1 && selectionState.absoluteEnd != -1)
+ {
+ var range:ElementRange = ElementRange.createElementRange(selectionState.textFlow, selectionState.absoluteStart, selectionState.absoluteEnd);
+ if (range)
+ {
+ var linkString:String = defaultLinkText;
+ _linkEl = range.firstLeaf.getParentByType(LinkElement) as LinkElement;
+ if (_linkEl != null)
+ {
+ var linkElStart:int = _linkEl.getAbsoluteStart();
+ var linkElEnd:int = linkElStart + _linkEl.textLength;
+ if (linkElEnd < linkElStart)
+ {
+ var temp:int = linkElStart;
+ linkElStart = linkElEnd;
+ linkElEnd = temp;
+ }
+
+ var beginRange:int = range.absoluteStart;
+ var endRange:int = range.absoluteEnd;
+
+ var beginPara:ParagraphElement = range.firstParagraph;
+ if (endRange == (beginPara.getAbsoluteStart() + beginPara.textLength))
+ {
+ endRange--;
+ }
+
+ if ((beginRange == endRange) || (endRange <= linkElEnd))
+ {
+ linkString = LinkElement(_linkEl).href;
+ }
+ }
+ var newLinkSelected:Boolean = _linkEl != null;
+ if (_linkSelected != newLinkSelected)
+ {
+ _linkSelected = newLinkSelected;
+ this.dispatchEvent(new Event("linkSelectedChange"));
+ }
+
+ this.text = linkString;
+
+ lastRange = range;
+ }
+ else
+ {
+ lastRange = null;
+ }
+ }
+
+ enabled = _textArea.selectionAnchorPosition != _textArea.selectionActivePosition || _linkSelected;
+ }
+
+ /**
+ * @private
+ * Return true if the character is a whitespace character
+ */
+ private function isWhitespace(charCode:uint):Boolean
+ {
+ return charCode === 0x0009 || charCode === 0x000A || charCode === 0x000B || charCode === 0x000C || charCode === 0x000D || charCode === 0x0020 || charCode === 0x0085 || charCode === 0x00A0 || charCode === 0x1680 || charCode === 0x180E || charCode === 0x2000 || charCode === 0x2001 || charCode === 0x2002 || charCode === 0x2003 || charCode === 0x2004 || charCode === 0x2005 || charCode === 0x2006 || charCode === 0x2007 || charCode === 0x2008 || charCode === 0x2009 || charCode === 0x200A || charCode === 0x2028 || charCode === 0x2029 || charCode === 0x202F || charCode === 0x205F || charCode === 0x3000;
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:TextInput>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/RichTextEditorToolBar.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/RichTextEditorToolBar.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/RichTextEditorToolBar.mxml
new file mode 100755
index 0000000..d7ef167
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/RichTextEditorToolBar.mxml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:HGroup gap="6" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:richTextEditorClasses="spark.components.richTextEditorClasses.*"
+ xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Metadata>
+ [Event(name="linkSelectedChange", type="flash.events.Event")]
+ </fx:Metadata>
+ <fx:Script>
+ <![CDATA[
+ import mx.collections.IList;
+ import spark.components.TextArea;
+
+ [Bindable]
+ /**
+ * A list of fonts for the font dropdown
+ */
+ public var fonts:IList = null;
+
+ [Bindable]
+ /**
+ * A list of sizes for the size dropdown
+ */
+ public var sizes:IList = null;
+
+ private var _linkSelected:Boolean = false;
+ private var _textArea:TextArea;
+
+ [Bindable("linkSelectedChange")]
+ /**
+ * True if a link is currently selected
+ */
+ public function get linkSelected():Boolean
+ {
+ return _linkSelected;
+ }
+
+ /**
+ * The textArea that this toolbar is controlling
+ */
+ [Bindable]
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ _textArea = value;
+ }
+
+ /**
+ * @private
+ */
+ private function handleLinkSelectedChange(e:Event):void
+ {
+ _linkSelected = (e.currentTarget as LinkTool).linkSelected;
+ this.dispatchEvent(new Event("linkSelectedChange"));
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+ <richTextEditorClasses:FontTool dataProvider="{fonts}" textArea="{textArea}"/>
+ <richTextEditorClasses:SizeTool dataProvider="{sizes}" textArea="{textArea}"/>
+ <s:HGroup gap="0">
+ <richTextEditorClasses:BoldTool textArea="{textArea}"/>
+ <richTextEditorClasses:ItalicTool textArea="{textArea}"/>
+ <richTextEditorClasses:UnderlineTool textArea="{textArea}"/>
+ </s:HGroup>
+ <richTextEditorClasses:ColorTool textArea="{textArea}"/>
+ <s:Line height="100%">
+ <s:stroke>
+ <s:SolidColorStroke color="#B3C2B8"/>
+ </s:stroke>
+ </s:Line>
+ <richTextEditorClasses:AlignTool textArea="{textArea}"/>
+ <richTextEditorClasses:BulletTool textArea="{textArea}"/>
+ <s:Line height="100%">
+ <s:stroke>
+ <s:SolidColorStroke color="#B3C2B8"/>
+ </s:stroke>
+ </s:Line>
+ <richTextEditorClasses:LinkTool linkSelectedChange="handleLinkSelectedChange(event)" textArea="{textArea}"/>
+</s:HGroup>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/SizeTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/SizeTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/SizeTool.mxml
new file mode 100644
index 0000000..0f9b6e6
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/SizeTool.mxml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:DropDownList width="60" change="callLater(handleChange, [event]);" dataProvider="{null}" mouseFocusEnabled="false" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
+ xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.collections.ArrayList;
+ import mx.collections.IList;
+ import mx.events.FlexEvent;
+ import mx.utils.ArrayUtil;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private const _defaultDataProvider:ArrayList = new ArrayList([8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]);
+ private var _textArea:TextArea;
+
+ public override function set dataProvider(value:IList):void
+ {
+ if (value == null)
+ {
+ super.dataProvider = _defaultDataProvider;
+ }
+ else
+ {
+ super.dataProvider = value;
+ }
+ }
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleChange(e:Event):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.fontSize = this.selectedItem;
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ this.selectedItem = format.fontSize;
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:DropDownList>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/UnderlineTool.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/UnderlineTool.mxml b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/UnderlineTool.mxml
new file mode 100644
index 0000000..1ae0663
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/components/richTextEditorClasses/UnderlineTool.mxml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+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.
+
+-->
+<s:ToggleButton width="20" click="handleClick(event);" icon="@Embed('../../../../assets/tools/underline.png')" mouseFocusEnabled="false" toolTip="Underline text"
+ xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
+ <fx:Script>
+ <![CDATA[
+ import flash.text.engine.FontPosture;
+ import flashx.textLayout.formats.TextDecoration;
+ import flashx.textLayout.formats.TextLayoutFormat;
+ import mx.events.FlexEvent;
+ import spark.components.TextArea;
+ import spark.events.TextOperationEvent;
+
+ private var _textArea:TextArea;
+
+ /**
+ * The textArea that this component interacts with
+ */
+ public function get textArea():TextArea
+ {
+ return _textArea;
+ }
+
+ /**
+ * @private
+ */
+ public function set textArea(value:TextArea):void
+ {
+ if (_textArea)
+ {
+ _textArea.removeEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange);
+ }
+ _textArea = value;
+ if (_textArea)
+ {
+ _textArea.addEventListener(FlexEvent.SELECTION_CHANGE, handleSelectionChange, false, 0, true);
+ handleSelectionChange();
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function handleClick(e:MouseEvent):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ format.textDecoration = (format.textDecoration == TextDecoration.UNDERLINE) ? TextDecoration.NONE : TextDecoration.UNDERLINE;
+ _textArea.setFormatOfRange(format, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ _textArea.setFocus();
+ _textArea.dispatchEvent(new TextOperationEvent(TextOperationEvent.CHANGE));
+ }
+
+ /**
+ * @private
+ */
+ private function handleSelectionChange(e:FlexEvent = null):void
+ {
+ var format:TextLayoutFormat = _textArea.getFormatOfRange(null, _textArea.selectionAnchorPosition, _textArea.selectionActivePosition);
+ if (format.textDecoration == TextDecoration.UNDERLINE)
+ {
+ this.selected = true;
+ }
+ else
+ {
+ this.selected = false;
+ }
+ }
+ ]]>
+ </fx:Script>
+ <fx:Declarations>
+ <!-- Place non-visual elements (e.g., services, value objects) here -->
+ </fx:Declarations>
+</s:ToggleButton>
http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/d4eeb05f/frameworks/projects/experimental/src/spark/skins/AlignToolSkin.mxml
----------------------------------------------------------------------
diff --git a/frameworks/projects/experimental/src/spark/skins/AlignToolSkin.mxml b/frameworks/projects/experimental/src/spark/skins/AlignToolSkin.mxml
new file mode 100644
index 0000000..36e58b3
--- /dev/null
+++ b/frameworks/projects/experimental/src/spark/skins/AlignToolSkin.mxml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+
+
+<!--- The default skin class for the Spark ButtonBar component. The buttons on the ButtonBar component
+ use the ButtonBarLastButtonSkin, ButtonBarFirstButtonSkin and ButtonBarMiddleButtonSkin classes.
+
+ @see spark.components.ButtonBar
+ @see spark.components.ButtonBarButton
+
+ @langversion 3.0
+ @playerversion Flash 10
+ @playerversion AIR 1.5
+ @productversion Flex 4
+-->
+<s:Skin alpha.disabled="0.5" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
+
+ <fx:Metadata>
+ <![CDATA[
+ /**
+ * @copy spark.skins.spark.ApplicationSkin#hostComponent
+ */
+ [HostComponent("spark.components.ButtonBar")]
+ ]]>
+ </fx:Metadata>
+
+ <s:states>
+ <s:State name="normal"/>
+ <s:State name="disabled"/>
+ </s:states>
+
+ <fx:Declarations>
+ <!---
+ @copy spark.components.ButtonBar#firstButton
+ @default spark.skins.spark.ButtonBarFirstButtonSkin
+ @see spark.skins.spark.ButtonBarFirstButtonSkin
+ -->
+ <fx:Component id="firstButton">
+ <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarFirstButtonSkin" toolTip="{data.toolTip}"/>
+ </fx:Component>
+
+ <!---
+ @copy spark.components.ButtonBar#middleButton
+ @default spark.skins.spark.ButtonBarMiddleButtonSkin
+ @see spark.skins.spark.ButtonBarMiddleButtonSkin
+ -->
+ <fx:Component id="middleButton">
+ <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarMiddleButtonSkin" toolTip="{data.toolTip}"/>
+ </fx:Component>
+
+ <!---
+ @copy spark.components.ButtonBar#lastButton
+ @default spark.skins.spark.ButtonBarLastButtonSkin
+ @see spark.skins.spark.ButtonBarLastButtonSkin
+ -->
+ <fx:Component id="lastButton">
+ <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarLastButtonSkin" toolTip="{data.toolTip}"/>
+ </fx:Component>
+
+ </fx:Declarations>
+
+ <!--- @copy spark.components.SkinnableDataContainer#dataGroup -->
+ <s:DataGroup id="dataGroup" height="100%" width="100%">
+ <s:layout>
+ <s:ButtonBarHorizontalLayout gap="-1"/>
+ </s:layout>
+ </s:DataGroup>
+
+</s:Skin>