Hugo Ferreira created FLEX-35373:
------------------------------------

             Summary: TLF - Leader dots/dash/underscore
                 Key: FLEX-35373
                 URL: https://issues.apache.org/jira/browse/FLEX-35373
             Project: Apache Flex
          Issue Type: New Feature
          Components: TLF
    Affects Versions: Apache Flex 4.14.1
         Environment: Flex + AIR + TLF
            Reporter: Hugo Ferreira
            Priority: Critical


Flex TLF it's a great text framework under the FTE (the engine), however the 
FTE does not provide a way for a feature called leader tabs in ms word (see 
https://support.office.com/en-us/article/Show-dots-or-leaders-between-tabs-c80b62d0-2244-4078-95bd-8c82f91440ba?ui=en-US&rs=en-US&ad=US).
This is a critical/blocker feature for many types of letters and after a deep 
search, I didn't find anyone that had implemented and provided this feature, so 
I decided implement it my self in TLF layer and share with Flex community (may 
be not perfect and you are free to adjust or improve but the base is there and 
works for me).

This is the new LeaderOperation main class:
{code:java}
package flashx.textLayout.operations
{
        import flash.text.engine.TextLine;

        import flashx.textLayout.edit.EditManager;
        import flashx.textLayout.edit.SelectionState;
        import flashx.textLayout.operations.FlowTextOperation;
        import flashx.textLayout.operations.InsertTextOperation;

        import mx.utils.StringUtil;

        public class LeaderOperation extends FlowTextOperation
        {
                private var insertEndLeaderOperation:InsertTextOperation = null;

                public var leaderType:String;
                public var linePosition:int;

                public function LeaderOperation(operationState:SelectionState)
                {
                        super(operationState);
                }

                public static function getLeader(text:String):Leader
                {
                        var index:int = 
text.indexOf(StringUtil.repeat(Leader.TYPE_DOT, 4));
                        if (index > -1)
                                return new Leader(Leader.TYPE_DOT, index);

                        index = 
text.indexOf(StringUtil.repeat(Leader.TYPE_DASH, 4));
                        if (index > -1)
                                return new Leader(Leader.TYPE_DASH, index);

                        index = 
text.indexOf(StringUtil.repeat(Leader.TYPE_UNDERSCORE, 4));
                        if (index > -1)
                                return new Leader(Leader.TYPE_UNDERSCORE, 
index);

                        return null;
                }

                public function createLeader(leaderType:String, 
linePosition:int):void
                {
                        if (textFlow.interactionManager is EditManager)
                        {
                                var operationState:SelectionState = 
originalSelectionState;
                                var editManager:EditManager = 
textFlow.interactionManager as EditManager;

                                if (operationState != null)
                                {
                                        var numLines:int = 
textFlow.flowComposer.numLines;
                                        var line:TextLine = 
textFlow.flowComposer.findLineAtPosition(linePosition).getTextLine();

                                        while (numLines == 
textFlow.flowComposer.numLines)
                                        {
                                                var leader:LeaderOperation = 
new LeaderOperation(operationState);
                                                leader.leaderType = leaderType;
                                                leader.linePosition = 
linePosition;
                                                editManager.doOperation(leader);
                                        }

                                        editManager.undo();
                                }
                        }
                }
                
                public override function doOperation():Boolean
                {
                        insertEndLeaderOperation = new InsertTextOperation(new 
SelectionState(textFlow, linePosition + 1, linePosition + 1), leaderType);
                        insertEndLeaderOperation.doOperation();

                        return true;
                }
                
                public override function undo():SelectionState
                {
                        insertEndLeaderOperation.undo();
                        return originalSelectionState;
                }
        }
}
{code}

And this is the new Leader model class:
{code:java}
package flashx.textLayout.operations
{
        public class Leader
        {
                public static const TYPE_DOT:String = ".";
                public static const TYPE_DASH:String = "-";
                public static const TYPE_UNDERSCORE:String = "_";

                public var type:String;
                public var index:int;

                public function Leader(type:String, index:int)
                {
                        this.type = type;
                        this.index = index;
                }
        }
}
{code}

In EditManager class, replace the keyUpHandler function by this new version:
{code:java}
public override function keyUpHandler(event:KeyboardEvent):void
                {
                        if (!hasSelection() || event.isDefaultPrevented())
                                return;
                                
                        super.keyUpHandler(event);

                        var leader:Leader = 
LeaderOperation.getLeader(textFlow.getText(getSelectionState().absoluteStart));
                        if (leader != null)
                        {
                                var operationState:SelectionState = 
(textFlow.interactionManager as EditManager).defaultOperationState();
                                new 
LeaderOperation(operationState).createLeader(leader.type, 
getSelectionState().absoluteStart + leader.index);
                        }
                        
                        if ((textFlow.configuration.manageEnterKey && 
event.charCode == Keyboard.ENTER) || (textFlow.configuration.manageTabKey && 
event.charCode == Keyboard.TAB)) {
                                event.stopImmediatePropagation();
                        }
                }
{code}

In InsertTextOperation class, replace the doOperation function by this new 
version:
{code:java}
                public override function doOperation():Boolean
                {
                        doInternal();

                        if (_text != "" && _text != Leader.TYPE_DOT && _text != 
Leader.TYPE_DASH && _text != Leader.TYPE_UNDERSCORE)
                        {
                                var leader:Leader = 
LeaderOperation.getLeader(textFlow.getText(originalSelectionState.absoluteStart));
                                if (leader != null)
                                        new InsertTextOperation(new 
SelectionState(textFlow, originalSelectionState.absoluteStart + leader.index,
                                                
originalSelectionState.absoluteStart + leader.index + 2), "").doOperation();
                        }

                        return true;
                }
{code}

If the developer final project, if he want to start a dot leader in the 
selected line, this is the method do to that:

{code:java}
                public function createDotLeader():void
                {
                        var editManager:EditManager = 
textFlow.interactionManager as EditManager;
                        var lineIndex:int = 
textFlow.flowComposer.findLineIndexAtPosition(editManager.defaultOperationState().absoluteEnd);
                        var totalChars:int = 
textFlow.flowComposer.findLineAtPosition(editManager.defaultOperationState().absoluteEnd).getTextLine().atomCount;

                        for (var i:int = 0; i < lineIndex; i++)
                        {
                                totalChars += 
textFlow.flowComposer.getLineAt(i).getTextLine().atomCount;
                        }

                        new 
LeaderOperation(editManager.defaultOperationState()).createLeader(Leader.TYPE_DOT,
 totalChars - 2);
                }
{code}

Final thoughts:
- The leader is started by defined a specific line with 3 possibilities (dot, 
dash, underscore);
- When the user change the line (add text or delete text) or even the 
paragraph, the leader is automatically adjusted to fit on the line !
- This works even after save and reload the tlf data however a better approach 
could be a new type of format to not depend on the numbers of .... or ---- or 
____ (works for me and it's a very good first version but it's not bullet 
proof).



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to