| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 flashx.textLayout.conversion |
| { |
| import flash.system.System; |
| |
| import flashx.textLayout.TextLayoutVersion; |
| import flashx.textLayout.tlf_internal; |
| import flashx.textLayout.debug.assert; |
| import flashx.textLayout.elements.BreakElement; |
| import flashx.textLayout.elements.Configuration; |
| import flashx.textLayout.elements.ContainerFormattedElement; |
| import flashx.textLayout.elements.FlowElement; |
| import flashx.textLayout.elements.FlowGroupElement; |
| import flashx.textLayout.elements.FlowLeafElement; |
| import flashx.textLayout.elements.GlobalSettings; |
| import flashx.textLayout.elements.IConfiguration; |
| import flashx.textLayout.elements.ListElement; |
| import flashx.textLayout.elements.ListItemElement; |
| import flashx.textLayout.elements.ParagraphElement; |
| import flashx.textLayout.elements.ParagraphFormattedElement; |
| import flashx.textLayout.elements.SpanElement; |
| import flashx.textLayout.elements.TabElement; |
| import flashx.textLayout.elements.TableCellElement; |
| import flashx.textLayout.elements.TextFlow; |
| import flashx.textLayout.property.Property; |
| |
| use namespace tlf_internal; |
| |
| /** |
| * BaseTextLayoutImporter is a base class for handling the import/export of TextLayout text |
| * in the native format. |
| */ |
| internal class BaseTextLayoutImporter extends ConverterBase implements ITextImporter |
| { |
| private var _ns:Namespace; // namespace of expected in imported/exported content |
| |
| private var _textFlowNamespace:Namespace; // namespace of the TextFlow element against which the namespaces of the following elements are validated |
| |
| protected var _config:ImportExportConfiguration; |
| protected var _textFlowConfiguration:IConfiguration = null; |
| protected var _importVersion:uint; |
| |
| // static private const anyPrintChar:RegExp = /[^\s]/g; |
| // Consider only tab, line feed, carriage return, and space as characters used for pretty-printing. |
| // While debatable, this is consistent with what CSS does. |
| static private const anyPrintChar:RegExp = /[^\u0009\u000a\u000d\u0020]/g; |
| |
| public function BaseTextLayoutImporter(nsValue:Namespace, config:ImportExportConfiguration) |
| { |
| _ns = nsValue; |
| _config = config; |
| } |
| |
| tlf_internal override function clear():void |
| { |
| super.clear(); |
| _textFlowNamespace = null; |
| _impliedPara = null; |
| } |
| |
| /** @copy ITextImporter#importToFlow() |
| */ |
| public function importToFlow(source:Object):TextFlow |
| { |
| clear(); // empty results of previous imports |
| |
| if (throwOnError) |
| return importToFlowCanThrow(source); |
| |
| var rslt:TextFlow = null; |
| var savedErrorHandler:Function = Property.errorHandler; |
| try |
| { |
| Property.errorHandler = importPropertyErrorHandler; |
| rslt = importToFlowCanThrow(source); |
| } |
| catch (e:Error) |
| { |
| reportError(e.toString()); |
| } |
| Property.errorHandler = savedErrorHandler; |
| return rslt; |
| } |
| |
| /** @copy ITextImporter#get configuration() |
| */ |
| public function get configuration():IConfiguration |
| { |
| return _textFlowConfiguration; |
| } |
| |
| public function set configuration(value:IConfiguration):void |
| { |
| _textFlowConfiguration = value; |
| } |
| |
| /** @private */ |
| protected function importPropertyErrorHandler(p:Property,value:Object):void |
| { |
| reportError(Property.createErrorString(p,value)); |
| } |
| |
| private function importToFlowCanThrow(source:Object):TextFlow |
| { |
| if (source is String) |
| return importFromString(String(source)); |
| else if (source is XML) |
| return importFromXML(XML(source)); |
| return null; |
| } |
| |
| /** Parse and convert input data. |
| * |
| * @param source - a string which is in XFL format. String is applied to an XML object then passed |
| * to importFromXML to be processed. The source must be capable of being cast as an XML |
| * object (E4X). |
| */ |
| protected function importFromString(source:String):TextFlow |
| { |
| var originalSettings:Object = XML.settings(); |
| try |
| { |
| XML.ignoreProcessingInstructions = false; |
| XML.ignoreWhitespace = false; |
| var xmlTree:XML = new XML(source); |
| } |
| finally |
| { |
| XML.setSettings(originalSettings); |
| } |
| |
| var textFlow:TextFlow = importFromXML(xmlTree); |
| if (Configuration.playerEnablesArgoFeatures) |
| System["disposeXML"](xmlTree); |
| return textFlow; |
| } |
| |
| /** Parse and convert input data. |
| * |
| * xflSource is a XFL formated object which must be capable of being cast as an XML |
| * object (E4X). |
| */ |
| protected function importFromXML(xmlSource:XML):TextFlow |
| // Parse an XFL hierarchy into a TextFlow, using the geometry supplied by a TextFrame |
| // to host child containers (e.g. tables). This is the main entry point into this class. |
| { |
| return parseContent(xmlSource[0]); |
| } |
| |
| // This routine imports a TextFlow |
| protected function parseContent(rootStory:XML):TextFlow |
| { |
| // If the root element isn't a textFlow we know how to parse, keep descending the hierarchy. |
| var child:XML = rootStory..*::TextFlow[0]; |
| if (child) |
| return parseTextFlow(this, rootStory); |
| return null; |
| } |
| |
| /** Returns the namespace used in for writing XML/XFL |
| * |
| * @return the Namespace being used. |
| */ |
| public function get ns(): Namespace |
| { |
| return _ns; |
| } |
| |
| // Remove double spaces, tabs, and newlines. |
| // If I have a sequence of different sorts of spaces (e.g., en quad, hair space), would I want them converted down to one space? Probably not. |
| // For now, u0020 is the only space character we consider for eliminating duplicates, though u00A0 (non-breaking space) is potentially eligible. |
| static private const dblSpacePattern:RegExp = /[\u0020]{2,}/g; |
| // Tab, line feed, and carriage return |
| static private const tabNewLinePattern:RegExp = /[\u0009\u000a\u000d]/g; |
| protected static function stripWhitespace(insertString:String):String |
| { |
| // Replace the newlines and tabs inside the element with spaces. |
| return insertString.replace(tabNewLinePattern, " "); |
| } |
| |
| /** Parse XML and convert to TextFlow. |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent always null - this parameter is only provided to match FlowElementInfo.importer signature |
| * @return TextFlow the new TextFlow created as a result of the parse |
| */ |
| static public function parseTextFlow(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:Object=null):TextFlow |
| { |
| return importer.createTextFlowFromXML(xmlToParse, null); |
| } |
| |
| /** |
| * Static method to parse the supplied XML into a paragrph. |
| * Parse the <p ...> tag and it's children. |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parsePara(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var paraElem:ParagraphElement = importer.createParagraphFromXML(xmlToParse); |
| if (importer.addChild(parent, paraElem)) |
| { |
| importer.parseFlowGroupElementChildren(xmlToParse, paraElem); |
| //if parsing an empty paragraph, create a Span for it. |
| if (paraElem.numChildren == 0) |
| paraElem.addChild(new SpanElement()); |
| } |
| } |
| |
| static protected function copyAllStyleProps(dst:FlowLeafElement,src:FlowLeafElement):void |
| { |
| dst.format = src.format; |
| dst.typeName = src.typeName; |
| dst.id = src.id; |
| } |
| |
| /** |
| * Static method for constructing a span from XML. Parse the <span> ... </span> tag. |
| * Insert the span into its parent |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parseSpan(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var firstSpan:SpanElement = importer.createSpanFromXML(xmlToParse); |
| |
| var elemList:XMLList = xmlToParse[0].children(); |
| if(elemList.length() == 0) |
| { |
| // Empty span, but may have formatting, so don't strip it out. |
| // Note: the normalizer may yet strip it out if it is not the last child, but that's the normalizer's business. |
| importer.addChild(parent, firstSpan); |
| return; |
| } |
| |
| for each (var child:XML in elemList) |
| { |
| var elemName:String = child.name() ? child.name().localName : null; |
| |
| if (elemName == null) // span text |
| { |
| if (firstSpan.parent == null) // hasn't been used yet |
| { |
| firstSpan.text = child.toString(); |
| importer.addChild(parent, firstSpan); |
| } |
| else |
| { |
| var s:SpanElement = new SpanElement(); // No PMD |
| copyAllStyleProps(s,firstSpan); |
| s.text = child.toString(); |
| importer.addChild(parent, s); |
| } |
| } |
| else if (elemName == "br") |
| { |
| var brElem:BreakElement = importer.createBreakFromXML(child); // may be null |
| if (brElem) |
| { |
| copyAllStyleProps(brElem,firstSpan); |
| importer.addChild(parent, brElem); |
| } |
| else |
| importer.reportError(GlobalSettings.resourceStringFunction("unexpectedXMLElementInSpan",[ elemName ])); |
| } |
| else if (elemName == "tab") |
| { |
| var tabElem:TabElement = importer.createTabFromXML(child); // may be null |
| if (tabElem) |
| { |
| copyAllStyleProps(tabElem,firstSpan); |
| importer.addChild(parent, tabElem); |
| } |
| else |
| importer.reportError(GlobalSettings.resourceStringFunction("unexpectedXMLElementInSpan",[ elemName ])); |
| } |
| else |
| importer.reportError(GlobalSettings.resourceStringFunction("unexpectedXMLElementInSpan",[ elemName ])); |
| } |
| } |
| |
| /** |
| * Static method for constructing a break element from XML. Validate the <br> ... </br> tag. |
| * Use "\u2028" as the text; Insert the new element into its parent |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parseBreak(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var breakElem:BreakElement = importer.createBreakFromXML(xmlToParse); |
| importer.addChild(parent, breakElem); |
| } |
| |
| /** |
| * Static method for constructing a tab element from XML. Validate the <tab> ... </tab> tag. |
| * Use "\t" as the text; Insert the new element into its parent |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parseTab(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var tabElem:TabElement = importer.createTabFromXML(xmlToParse); // may be null |
| if (tabElem) |
| importer.addChild(parent, tabElem); |
| } |
| |
| /** |
| * Static method for constructing a list element from XML. |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parseList(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var listElem:ListElement = importer.createListFromXML(xmlToParse); |
| if (importer.addChild(parent, listElem)) |
| { |
| importer.parseFlowGroupElementChildren(xmlToParse, listElem); |
| } |
| } |
| |
| /** |
| * Static method for constructing a list item from XML. |
| * |
| * @param importer parser object |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| static public function parseListItem(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| var listItem:ListItemElement = importer.createListItemFromXML(xmlToParse); |
| if (importer.addChild(parent, listItem)) |
| { |
| importer.parseFlowGroupElementChildren(xmlToParse, listItem); |
| //if parsing an empty list item, create a Paragraph for it. |
| if (listItem.numChildren == 0) |
| listItem.addChild(new ParagraphElement()); |
| } |
| } |
| |
| protected function checkNamespace(xmlToParse:XML):Boolean |
| { |
| var elementNS:Namespace = xmlToParse.namespace(); |
| if (!_textFlowNamespace) // Not set yet; must be parsing the TextFlow element |
| { |
| // TextFlow element: allow only empty namespace and flow namespace |
| if (elementNS != ns) |
| { |
| reportError(GlobalSettings.resourceStringFunction("unexpectedNamespace", [elementNS.toString()])); |
| return false; |
| } |
| _textFlowNamespace = elementNS; |
| } |
| // Other elements: must match the namespace of the TextFlow element |
| // Specifically, can't be empty unless the TextFlow element's namespace is also empty |
| else if (elementNS != _textFlowNamespace) |
| { |
| reportError(GlobalSettings.resourceStringFunction("unexpectedNamespace", [elementNS.toString()])); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| public function parseAttributes(xmlToParse:XML,formatImporters:Array):void |
| { |
| var importer:IFormatImporter; |
| // reset them all |
| for each (importer in formatImporters) |
| importer.reset(); |
| |
| if (!xmlToParse) |
| return; |
| |
| for each (var item:XML in xmlToParse.attributes()) |
| { |
| var propertyName:String = item.name().localName; |
| var propertyValue:String = item.toString(); |
| var imported:Boolean = false; |
| |
| // Strip out padding properties from XML coming in before TLF 2.0, since they were ignored but are no longer. This preserves the look of the text. |
| if (xmlToParse.localName() == "TextFlow") |
| { |
| if (propertyName == "version") // skip over the version attribute, we've already processed it |
| continue; |
| } |
| else if (_importVersion < TextLayoutVersion.VERSION_2_0 && |
| (propertyName == "paddingLeft" || propertyName == "paddingTop" || propertyName == "paddingRight" || propertyName == "paddingBottom")) |
| continue; |
| for each (importer in formatImporters) |
| { |
| if (importer.importOneFormat(propertyName,propertyValue)) |
| { |
| imported = true; |
| break; |
| } |
| } |
| if (!imported) // not a supported attribute |
| handleUnknownAttribute (xmlToParse.name().localName, propertyName); |
| } |
| } |
| |
| static protected function extractAttributesHelper(curAttrs:Object, importer:TLFormatImporter):Object |
| { |
| if (curAttrs == null) |
| return importer.result; |
| |
| if (importer.result == null) |
| return curAttrs; |
| |
| var workAttrs:Object = new importer.classType(curAttrs); |
| workAttrs.apply(importer.result); |
| return workAttrs; |
| } |
| |
| /** |
| * Parse XML and convert to TextFlow. |
| * |
| * @param xmlToParse content to parse |
| * @param textFlow TextFlow we're parsing. If null, create or find a new TextFlow based on XML content |
| * @return TextFlow the new TextFlow created as a result of the parse |
| */ |
| public function createTextFlowFromXML(xmlToParse:XML, newFlow:TextFlow = null):TextFlow // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createTextFlowFromXML"); } |
| return null; |
| } |
| |
| public function createParagraphFromXML(xmlToParse:XML):ParagraphElement // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createParagraphFromXML"); } |
| return null; |
| } |
| |
| public function createSpanFromXML(xmlToParse:XML):SpanElement // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createSpanFromXML"); } |
| return null; |
| } |
| |
| public function createBreakFromXML(xmlToParse:XML):BreakElement |
| { |
| parseAttributes(xmlToParse,null); // no attributes allowed - reports errors |
| return new BreakElement(); |
| } |
| |
| public function createListFromXML(xmlToParse:XML):ListElement // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createListFromXML"); } |
| return null; |
| } |
| |
| public function createListItemFromXML(xmlToParse:XML):ListItemElement // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createListItemFromXML"); } |
| return null; |
| } |
| |
| public function createTabFromXML(xmlToParse:XML):TabElement |
| { |
| parseAttributes(xmlToParse,null); // reports errors |
| return new TabElement(); |
| } |
| |
| /** |
| * Parse XML, convert to FlowElements and add to the parent. |
| * |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| */ |
| public function parseFlowChildren(xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| parseFlowGroupElementChildren(xmlToParse, parent); |
| } |
| |
| /** |
| * Parse XML, convert to FlowElements and add to the parent. |
| * |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| * @param chainedParent whether parent actually corresponds to xmlToParse or has been chained (such as when xmlToParse is a formatting element) |
| */ |
| public function parseFlowGroupElementChildren(xmlToParse:XML, parent:FlowGroupElement, exceptionElements:Object = null, chainedParent:Boolean=false):void |
| { |
| for each (var child:XML in xmlToParse.children()) |
| { |
| if (child.nodeKind() == "element") |
| { |
| parseObject(child.name().localName, child, parent, exceptionElements); |
| } |
| // look for mixed content here |
| else if (child.nodeKind() == "text") |
| { |
| var txt:String = child.toString(); |
| // Strip whitespace-only text appearing as a child of a container-formatted element |
| var strip:Boolean = false; |
| if (parent is ContainerFormattedElement) |
| { |
| strip = txt.search(anyPrintChar) == -1; |
| } |
| |
| if (!strip) |
| addChild(parent, createImpliedSpan(txt)); |
| } |
| } |
| |
| // no implied paragraph should extend across container elements |
| if (!chainedParent && parent is ContainerFormattedElement) |
| resetImpliedPara(); |
| } |
| |
| /** |
| * Parse XML, convert XML to FlowElements and TextFlow and add to the parent table cell |
| * |
| * @param xmlToParse content to parse |
| * @param parent the parent for the new content |
| * @param chainedParent whether parent actually corresponds to xmlToParse or has been chained (such as when xmlToParse is a formatting element) |
| */ |
| public function parseTableCellElementChildren(xmlToParse:XML, parent:FlowGroupElement, exceptionElements:Object = null, chainedParent:Boolean=false):void |
| { |
| var textFlow:TextFlow; |
| |
| for each (var child:XML in xmlToParse.children()) |
| { |
| if (child.nodeKind() == "element") |
| { |
| if (child.name().localName=="p") { |
| textFlow = new TextFlow(); |
| parseObject(child.name().localName, child, textFlow, exceptionElements); |
| } |
| else if (child.name().localName=="TextFlow") { |
| TableCellElement(parent).textFlow = createTextFlowFromXML(child); |
| } |
| } |
| // look for mixed content here |
| else if (child.nodeKind() == "text") |
| { |
| var txt:String = child.toString(); |
| // Strip whitespace-only text appearing as a child of a container-formatted element |
| var strip:Boolean = false; |
| if (parent is ContainerFormattedElement) |
| { |
| strip = txt.search(anyPrintChar) == -1; |
| } |
| |
| if (!strip) { |
| textFlow = new TextFlow(); |
| parseObject(child.name().localName, child, textFlow, exceptionElements); |
| //addChild(textFlow, createImpliedSpan(txt)); |
| } |
| } |
| |
| if (textFlow) { |
| TableCellElement(parent).textFlow = textFlow; |
| textFlow = null; |
| } |
| } |
| } |
| |
| /** create an implied span with specified text */ |
| public function createImpliedSpan(text:String):SpanElement |
| { |
| var span:SpanElement = new SpanElement(); // No PMD |
| span.text = text; |
| return span; |
| } |
| |
| public function createParagraphFlowFromXML(xmlToParse:XML, newFlow:TextFlow = null):TextFlow // No PMD |
| { |
| CONFIG::debug { assert(false,"missing override for createParagraphFlowFromXML"); } // client must override |
| return null; |
| } |
| |
| tlf_internal function parseObject(name:String, xmlToParse:XML, parent:FlowGroupElement, exceptionElements:Object=null):void |
| { |
| if (!checkNamespace(xmlToParse)) |
| return; |
| |
| var info:FlowElementInfo = _config.lookup(name); |
| if (!info) |
| { |
| if (exceptionElements == null || exceptionElements[name] === undefined) |
| handleUnknownElement (name, xmlToParse, parent); |
| } |
| else |
| info.parser(this, xmlToParse, parent); |
| } |
| |
| protected function handleUnknownElement(name:String, xmlToParse:XML, parent:FlowGroupElement):void |
| { |
| reportError(GlobalSettings.resourceStringFunction("unknownElement", [ name ])); |
| } |
| |
| protected function handleUnknownAttribute(elementName:String, propertyName:String):void |
| { |
| reportError(GlobalSettings.resourceStringFunction("unknownAttribute", [ propertyName, elementName ])); |
| } |
| |
| protected function getElementInfo(xmlToParse:XML):FlowElementInfo |
| { |
| return _config.lookup(xmlToParse.name().localName); |
| } |
| |
| protected function GetClass(xmlToParse:XML):Class |
| { |
| var info:FlowElementInfo = _config.lookup(xmlToParse.name().localName); |
| return info ? info.flowClass : null; |
| } |
| |
| // In the text model, non-FlowParagraphElements (i.e. spans, images, links, TCY) cannot be children of a ContainerElement (TextFlow, Div etc.) |
| // They can only be children of paragraphs or subparagraph blocks. |
| // In XML, however, <p> elements can be implied (for example, a <span> may appear as a direct child of <flow>). |
| // So, while parsing the XML, if we enounter a non-FlowParagraphElement child of a ContainerElement |
| // 1. an explicitly created paragraph is used as the parent instead |
| // 2. such explicitly created paragraphs are shared by adjacent flow elements provided there isn't an intervening FlowParagraphElement |
| private var _impliedPara:ParagraphElement = null; |
| |
| /** @private */ |
| tlf_internal function createImpliedParagraph():ParagraphElement |
| { |
| return createParagraphFromXML(<p/>); |
| } |
| |
| /** |
| * @private |
| * Helper function for adding a child flow element that honors throwOnError setting and uses the parent override |
| * NOTE: You MUST NOT call addChild directly unless you are sure |
| * - There is not possibility of an implied paragraph, and |
| * - Parent is of type that can contain child |
| */ |
| tlf_internal function addChild(parent:FlowGroupElement, child:FlowElement):Boolean |
| { |
| if (child is ParagraphFormattedElement) |
| { |
| // Reset due to possibly intervening FlowParagrahElement; See note 2. above |
| resetImpliedPara(); |
| } |
| else if (parent is ContainerFormattedElement) |
| { |
| // See note 1. above |
| if (!_impliedPara) |
| { |
| // Derived classes may have special behavior for <p> tags. Implied paragraphs may need the same behavior. |
| // So call createParagraphFromXML, don't just instantiate a ParagraphElement |
| _impliedPara = createImpliedParagraph(); |
| parent.addChild(_impliedPara); |
| } |
| |
| parent = _impliedPara; |
| } |
| |
| if (throwOnError) |
| parent.addChild(child); |
| else |
| { |
| try |
| { |
| parent.addChild(child); |
| } |
| catch (e:*) |
| { |
| reportError(e); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| tlf_internal function resetImpliedPara():void |
| { |
| if (_impliedPara) |
| { |
| onResetImpliedPara(_impliedPara); |
| _impliedPara = null; |
| } |
| } |
| |
| protected function onResetImpliedPara(para:ParagraphElement):void |
| { |
| } |
| } |
| } |
| |