Как мне вставить SpanElement в TextFlow? - PullRequest
1 голос
/ 30 марта 2012

Мне нужна возможность выделить некоторый текст в текстовой области, а затем заменить выделенный текст на SpanElement. Я не могу использовать TextLayoutFormat, потому что он не имеет свойства "id".

Как вставить диапазон в определенной позиции в текстовой области?

Ответы [ 2 ]

4 голосов
/ 03 апреля 2012

Есть несколько способов сделать это.В зависимости от структуры исходного текста вы можете использовать простой подход для замены текста или вам может потребоваться более общий подход, который может обрабатывать множество сценариев.

Две идеи, одна простая и одна, которая подходитобщее решение. Было бы любопытно увидеть другие подходы, я всегда узнаю что-то новое о TLF:)

Экспортируйте текст TLF в строку, сделайте замену, импортируйте строку вновый TLF TextFlow.

  1. Получить TextFlow из свойства textFlow Spark TextArea / TextInput
  2. Использовать TextFlow.getText (0, -1, "") чтобы получить строковое представление
  3. Выполните подстановку. Повторно импортируйте поток: Посмотрите на TextFlowUtil.importFromString
  4. Примените поток текста с предыдущего шага обратно к TextInput или TextArea's textFlow свойство.

Этот подход, вероятно, не самый эффективный. Обратите внимание, что вы также можете потерять все стили, примененные к тексту. Взгляните на класс TextConverter, который вы также можете использовать дляимпортировать текст в TLF с текстовым форматом. В частности, TextConvert.importToFlow ().

Используйте API TextFlow для доступа к FlowElement, содержащему ваш текст.

Удалите элементы, которые содержат исходный текст, подлежащий замене, добавьте текст замены, добавьте конечный текст. Более эффективно, чем выше. Обратите внимание, если вы знаете точную структуру вашего текста, вы можете сделать это намного проще ...

[Редактировать]

Вот пример, который делает оба:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx"
               width="800" height="600" xmlns:local="*">

    <fx:Script>
        <![CDATA[
            import flashx.textLayout.edit.ISelectionManager;
            import flashx.textLayout.elements.FlowElement;
            import flashx.textLayout.elements.TextFlow;

            import spark.utils.TextFlowUtil;

            private var flow:TextFlow;
            private var mgr:ISelectionManager;
            private var startIndex:int;
            private var endIndex:int;

            private function init():void
            {
                flow = texty.textFlow;
                mgr = flow.interactionManager;
                if (mgr.hasSelection())
                {
                    // determine start/end indexes of the selection
                    if (mgr.anchorPosition < mgr.activePosition)
                    {
                        startIndex = mgr.anchorPosition;
                        endIndex = mgr.activePosition;
                    }
                    else
                    {
                        startIndex = mgr.activePosition;
                        endIndex = mgr.anchorPosition;
                    }
                }
                else
                {
                    startIndex = 0;
                    endIndex = 0;
                }
            }

            private function replaceByImportText():void
            {
                init();
                if (mgr.hasSelection())
                {
                    var copy:String = flow.getText(0,-1,"<br/>");
                    // replace the text
                    copy = copy.substring(0,startIndex) + "*** You just replaced me ***" + copy.substring(endIndex);
                    // reimport - expensive (makes a new TextFlow) and probably looses some fidelity (styles, etc)
                    texty.textFlow = TextFlowUtil.importFromString(copy);
                }
            }

            private function replaceBySplittingFlowElements():void
            {
                init();
                if (mgr.hasSelection())
                {
                    // each call to splitAtPosition leaves the text before startIndex in the original FlowElement
                    // and returns a new FlowElement (TextFlow's in this case) w/the remaining text
                    var textToBeReplaced:FlowElement = flow.splitAtPosition(startIndex);
                    // chops out whatever was between start/end indexes
                    var remainingTextToAddBack:TextFlow = textToBeReplaced.splitAtPosition(endIndex - startIndex) as TextFlow;
                    // insert replacment text
                    var span:SpanElement = new SpanElement();
                    span.text = "Hi, I'm a replacement String.";
                    // assumes last element is a paragraph but it could be a div :)
                    var lastParagraph:ParagraphElement = flow.getChildAt(flow.numChildren -1) as ParagraphElement;
                    if (lastParagraph)
                    {
                        lastParagraph.addChild(span);
                        // merge the last paragraph w/the 1st paragraph of remaining text
                        var firstP:ParagraphElement = remainingTextToAddBack.getChildAt(0) as ParagraphElement;
                        if (firstP)
                        {
                            lastParagraph.replaceChildren( lastParagraph.numChildren, lastParagraph.numChildren, getParagraphChildren(firstP) );
                        }

                    }

                }
            }

            private function getParagraphChildren(p:ParagraphElement):Array
            {
                var kids:Array =[];
                var numKids:int = p.numChildren;
                for (var i:int = 0; i<numKids; i++)
                {
                    kids.push( p.getChildAt(i) );
                }
                return kids;
            }

        ]]>
    </fx:Script>

    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>

    <s:HGroup>
        <s:Button label="Replace by importing text" click="replaceByImportText()" />
        <s:Button label="Replace by using FlowElements" click="replaceBySplittingFlowElements()"/>
    </s:HGroup>


    <s:TextArea id="texty" top="40" left="40" right="40" bottom="40">
        <s:p>
            <s:span>
                <s:text>
                    Bacon ipsum dolor sit amet turducken pancetta short ribs tail anim pig.
                    In pastrami in, ball tip flank shankle beef ribs spare ribs deserunt pancetta esse cupidatat aliquip venison pork chop.
                    Pork loin commodo corned beef ullamco culpa dolore occaecat, capicola adipisicing ribeye bresaola sunt est. 
                    Commodo labore culpa ut, sausage ad meatloaf adipisicing.
                </s:text>
            </s:span>
            <s:br/>
        </s:p>

        <s:p>
            <s:span>
                <s:text>
                    Quis qui aliqua enim, rump jerky aute bresaola aliquip pig speck short loin.
                    Non ea eiusmod shoulder, consequat enim ribeye sed. Meatloaf tenderloin pork loin reprehenderit.
                    Enim rump eiusmod, tri-tip capicola in do frankfurter dolore.
                    Culpa elit meatball pariatur turducken, leberkas excepteur irure in pork belly shank consequat.
                    Sint biltong t-bone veniam shankle. Consectetur irure et minim.
                </s:text>
            </s:span>
            <s:br/>
        </s:p>

        <s:p>
            <s:span>
                <s:text>
                    Excepteur laborum non corned beef, est dolore pastrami jowl id.
                    Leberkas short ribs ham, tempor id sed esse. Officia eiusmod pork frankfurter leberkas cow, nisi qui filet mignon mollit swine bacon veniam.
                    Nostrud deserunt nulla ground round, shankle sausage aliqua ut frankfurter culpa.
                    Veniam hamburger spare ribs, ullamco dolor labore salami capicola short loin swine.
                </s:text>
            </s:span>
        </s:p>

    </s:TextArea>
</s:Application>
3 голосов
/ 17 июля 2012

Я хотел добавить некоторый код, так как я создал свой из этого здесь, а также потому, что почти нет примеров или документации по методу "splitAtPosition".

Этот код вставит FlowElement (flowElement) в любую позицию (индекс) в текстовом потоке (текстовый поток) - не забудьте запустить textflow.flowComposer.updateAllControllers(); после запуска функции:

private function insertFlowElementInTextFlowAt(textflow:TextFlow,index:int,flowElement:FlowElement):void{

    var part2:TextFlow = textflow.splitAtPosition(index) as TextFlow;
    var part2_firstPara:ParagraphElement = part2.getChildAt(0) as ParagraphElement;     
    var textflow_lastPara:ParagraphElement = textflow.getChildAt(textflow.numChildren -1) as ParagraphElement;  



    if (textflow.textLength == index){

        part2_firstPara.addChildAt(0,flowElement);
        textflow.replaceChildren(textflow.numChildren,textflow.numChildren,getFlowElementChildren(part2,0))

    }else if(index < textflow.textLength){

        textflow_lastPara.addChild(flowElement);
        textflow_lastPara.replaceChildren( textflow_lastPara.numChildren, textflow_lastPara.numChildren, getFlowElementChildren(part2_firstPara));
        textflow.replaceChildren(textflow.numChildren,textflow.numChildren,getFlowElementChildren(part2,1))

    }



}

private function getFlowElementChildren(p:FlowGroupElement,start:int=0):Array
{
    var kids:Array = new Array();
    for (var i:int = start; i<p.numChildren; i++){
        kids.push( p.getChildAt(i) );
    }
    return kids;
}
...