Uploaded image for project: 'Apache Flex'
  1. Apache Flex
  2. FLEX-35373

TLF - Leader dots/dash/underscore

    XMLWordPrintableJSON

Details

    • New Feature
    • Status: Open
    • Critical
    • Resolution: Unresolved
    • Apache Flex 4.14.1
    • None
    • TLF
    • None
    • Flex + AIR + TLF

    Description

      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:

      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;
      		}
      	}
      }
      

      And this is the new Leader model class:

      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;
      		}
      	}
      }
      

      In EditManager class, replace the keyUpHandler function by this new version:

      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();
      			}
      		}
      

      In InsertTextOperation class, replace the doOperation function by this new version:

      		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;
      		}
      

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

      		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);
      		}
      

      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).

      Attachments

        Activity

          People

            Unassigned Unassigned
            hferreira.80@gmail.com Hugo Ferreira
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated: