////////////////////////////////////////////////////////////////////////////////
//
// 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 UnitTest.Tests
{
import UnitTest.ExtendedClasses.TestSuiteExtended;
import UnitTest.ExtendedClasses.VellumTestCase;
import UnitTest.Fixtures.FileRepository;
import UnitTest.Fixtures.TestConfig;
import flash.display.Sprite;
import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.System;
import flash.text.engine.FontPosture;
import flash.text.engine.TextLineValidity;
import flash.utils.getQualifiedClassName;
import flashx.textLayout.compose.IFlowComposer;
import flashx.textLayout.container.ContainerController;
import flashx.textLayout.conversion.ConversionType;
import flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.edit.IEditManager;
import flashx.textLayout.edit.PointFormat;
import flashx.textLayout.edit.SelectionManager;
import flashx.textLayout.edit.SelectionState;
import flashx.textLayout.edit.TextClipboard;
import flashx.textLayout.edit.TextScrap;
import flashx.textLayout.elements.Configuration;
import flashx.textLayout.elements.DivElement;
import flashx.textLayout.elements.FlowElement;
import flashx.textLayout.elements.FlowGroupElement;
import flashx.textLayout.elements.FlowLeafElement;
import flashx.textLayout.elements.InlineGraphicElement;
import flashx.textLayout.elements.LinkElement;
import flashx.textLayout.elements.ListElement;
import flashx.textLayout.elements.ListItemElement;
import flashx.textLayout.elements.ParagraphElement;
import flashx.textLayout.elements.SpanElement;
import flashx.textLayout.elements.SubParagraphGroupElementBase;
import flashx.textLayout.elements.TCYElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.elements.TextRange;
import flashx.textLayout.events.*;
import flashx.textLayout.formats.*;
import flashx.textLayout.operations.DeleteTextOperation;
import flashx.textLayout.operations.PasteOperation;
import flashx.textLayout.operations.SplitElementOperation;
import flashx.textLayout.operations.SplitParagraphOperation;
import flashx.textLayout.tlf_internal;
import flashx.textLayout.utils.NavigationUtil;
import flashx.undo.IUndoManager;
import flashx.undo.UndoManager;
import mx.utils.LoaderUtil;
use namespace tlf_internal;
/** Test the state of selection after each operation is done, undone, and redone.
*/
public class OperationTest extends VellumTestCase
{
public function OperationTest(methodName:String, testID:String, testConfig:TestConfig, testCaseXML:XML=null)
{
super(methodName, testID, testConfig, testCaseXML);
TestData.fileName = "severalPages.xml";
// Note: These must correspond to a Watson product area (case-sensitive)
metaData.productArea = "Editing";
}
public static function suiteFromXML(testListXML:XML, testConfig:TestConfig, ts:TestSuiteExtended):void
{
FileRepository.readFile(testConfig.baseURL,"../../test/testFiles/markup/tlf/severalPages.xml");
var testCaseClass:Class = OperationTest;
VellumTestCase.suiteFromXML(testCaseClass, testListXML, testConfig, ts);
}
public override function setUp():void
{
super.setUp();
}
public override function tearDown():void
{
super.tearDown();
}
// Check that the actual selection matches what was expected
private function checkExpectedSelection(expectedStart:int, expectedEnd:int):void
{
var actualSelectionStart:int = SelManager.absoluteStart;
assertTrue("expected selection to start at " + expectedStart + " but got " + actualSelectionStart,
expectedStart == actualSelectionStart);
var actualSelectionEnd:int = SelManager.absoluteEnd;
assertTrue("expected selection to end at " + expectedEnd + " but got " + actualSelectionEnd,
expectedEnd == actualSelectionEnd);
}
private function resetSelection():void
{
SelManager.selectRange(-1,-1);
}
private function checkUndo(expectedStart:int, expectedEnd:int):void
{
resetSelection();
(SelManager as IEditManager).undo();
checkExpectedSelection(expectedStart, expectedEnd);
}
private function checkRedo(expectedStart:int, expectedEnd:int):void
{
resetSelection();
(SelManager as IEditManager).redo();
checkExpectedSelection(expectedStart, expectedEnd);
}
/**
* Test selection with the InsertTextOperation in insert (non-overwrite) mode
*/
public function insertTextSelectionTest():void
{
const textToInsert:String = "TEST";
const initialSelectionPosition:int = 10;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionPosition, initialSelectionPosition);
(SelManager as IEditManager).insertText(textToInsert);
SelManager.flushPendingOperations();
checkExpectedSelection(initialSelectionPosition + textToInsert.length, initialSelectionPosition + textToInsert.length);
// After undo, back to original caret selection
checkUndo(initialSelectionPosition, initialSelectionPosition);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionPosition + textToInsert.length, initialSelectionPosition + textToInsert.length);
}
/**
* Test selection with the InsertTextOperation in overwrite mode
*/
public function overwriteTextSelectionTest():void
{
const textToInsert:String = "T"; // Looks like overwrite mode only works with single characters
const initialSelectionPosition:int = 10;
var flowLength:int = SelManager.textFlow.textLength;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionPosition, initialSelectionPosition);
(SelManager as IEditManager).overwriteText(textToInsert);
SelManager.flushPendingOperations();
checkExpectedSelection(initialSelectionPosition + textToInsert.length, initialSelectionPosition + textToInsert.length);
assertTrue("Flow length changed after insert in overwrite mode", SelManager.textFlow.textLength == flowLength);
// After undo, back to original caret selection
checkUndo(initialSelectionPosition, initialSelectionPosition);
assertTrue("Flow length changed after undo insert in overwrite mode", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionPosition + textToInsert.length, initialSelectionPosition + textToInsert.length);
assertTrue("Flow length changed after redo insert in overwrite mode", SelManager.textFlow.textLength == flowLength);
}
public function splitParagraphTest():void
{
// Change the character format at the end of a para, insert a new para after, insert some text,
// it should have the char format from the previous para
SelManager.selectRange(0, 0);
var leaf:FlowLeafElement = SelManager.textFlow.findLeaf(0);
var para:ParagraphElement = leaf.getParagraph();
leaf = para.getLastLeaf();
var charFormat:TextLayoutFormat = new TextLayoutFormat(leaf.format);
charFormat.fontSize = Number(leaf.computedFormat.fontSize) * 2;
SelManager.selectRange(para.textLength - 2, para.textLength);
(SelManager as IEditManager).applyLeafFormat(charFormat);
SelManager.selectRange(para.textLength - 1, para.textLength - 1);
(SelManager as IEditManager).splitParagraph();
SelManager.selectRange(para.textLength, para.textLength);
(SelManager as IEditManager).insertText("HI THERE");
SelManager.flushPendingOperations();
leaf = SelManager.textFlow.findLeaf(para.textLength);
assertTrue("Failure inserting paragraph", leaf.getParagraph() != para);
assertTrue("Failure to pick up format from previous para", leaf.computedFormat.fontSize == charFormat.fontSize);
}
public function deleteTextSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).deleteNextCharacter();
checkExpectedSelection(initialSelectionStart, initialSelectionStart);
// After undo, deleted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to original state
checkRedo(initialSelectionStart, initialSelectionStart);
}
public function deleteNextWordTest():void
{
deleteNextWordFromCaret(10);
/* This test code not yet debugged -- basic problem is that nextWord can't accurately predict what should be deleted
SelManager.selectRange(343, 343);
SelManager.previousWord();
deleteNextWordFromRange(SelManager.absoluteStart, 652); // pick a position that is at the start of the word
var paragraph:ParagraphFormattedElement = SelManager.textFlow.findLeaf(343).getParagraph();
var paragraphEnd:int = paragraph.getAbsoluteStart() + paragraph.textLength - 1;
deleteNextWordFromRange(paragraphEnd, SelManager.textFlow.textLength - 10);
deleteNextWordFromCaret(paragraphEnd); */
}
private function deleteNextWordFromCaret(start:int):void
{
const initialSelection:int = start;
var flowLength:int = SelManager.textFlow.textLength;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelection, initialSelection);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
var wordSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.nextWord(wordSelState,true);
var wordLength:int = wordSelState.absoluteEnd - wordSelState.absoluteStart;
(SelManager as IEditManager).deleteNextWord();
checkExpectedSelection(initialSelection, initialSelection);
assertTrue("deleteNextWordTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
assertTrue("deleteNextWordTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(initialSelection, initialSelection);
assertTrue("deleteNextWordTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
}
public function deleteNextWordFromRange(anchorPosition:int, activePosition:int):void
{
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(anchorPosition, activePosition);
SelManager.selectRange(SelManager.absoluteStart, SelManager.absoluteStart);
var wordSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.nextWord(wordSelState,true);
var wordLength:int = wordSelState.absoluteEnd - wordSelState.absoluteStart;
// Try a range selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(anchorPosition, activePosition);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
(SelManager as IEditManager).deleteNextWord();
checkExpectedSelection(originalSelectionState.absoluteStart, originalSelectionState.absoluteStart);
assertTrue("deleteNextWordTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
// checkUndo(initialSelection, initialSelection + wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(originalSelectionState.absoluteStart, originalSelectionState.absoluteStart);
assertTrue("deleteNextWordTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
}
/*public function deleteNextPage():void
{
TestData.fileName = "severalPages.xml";
readTestFile(TestData.fileName);
var textRange:TextRange = new TextRange(SelManager.textFlow, 100, 200);
var aa:Boolean = NavigationUtil.nextPage(textRange);
}*/
public function deleteNextPageTest():void
{
var onePageRange:TextRange = new TextRange(SelManager.textFlow, 1, 5000);
var aa:Boolean = NavigationUtil.nextPage(onePageRange);
deletePreviousWordFromRange(5000, 10000);
}
public function deletePreviousPageTest():void
{
var onePageRange:TextRange = new TextRange(SelManager.textFlow, 5000, 10000);
var aa:Boolean = NavigationUtil.nextPage(onePageRange);
deletePreviousWordFromRange(1, 5000);
}
public function deletePreviousWordTest():void
{
deletePreviousWordFromCaret(10);
deletePreviousWordFromRange(347, 652);
// need case for start of paragraph - deletes previous newline
}
public function deletePreviousWordFromCaret(initialSelection:int):void
{
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(initialSelection, initialSelection);
SelManager.selectRange(SelManager.activePosition, SelManager.activePosition);
var wordSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.previousWord(wordSelState,true);
var wordLength:int = wordSelState.absoluteEnd - wordSelState.absoluteStart;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelection, initialSelection);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
(SelManager as IEditManager).deletePreviousWord();
checkExpectedSelection(initialSelection - wordLength, initialSelection - wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
// checkUndo(initialSelection, initialSelection + wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(initialSelection - wordLength, initialSelection - wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
}
public function deletePreviousWordFromRange(anchorPosition:int, activePosition:int):void
{
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(anchorPosition, activePosition);
SelManager.selectRange(SelManager.absoluteStart, SelManager.absoluteStart);
var wordSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.previousWord(wordSelState,true);
var wordLength:int = wordSelState.absoluteEnd - wordSelState.absoluteStart;
// Try a range selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(anchorPosition, activePosition);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
(SelManager as IEditManager).deletePreviousWord();
checkExpectedSelection(originalSelectionState.absoluteStart - wordLength, originalSelectionState.absoluteStart - wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
// checkUndo(initialSelection, initialSelection + wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(originalSelectionState.absoluteStart - wordLength, originalSelectionState.absoluteStart - wordLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - wordLength);
}
/** Test forward delete from a caret position */
public function deleteNextCharacterTest():void
{
const initialSelection:int = 10;
var flowLength:int = SelManager.textFlow.textLength;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelection, initialSelection);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
var characterSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.nextCharacter(characterSelState,true);
var characterLength:int = characterSelState.absoluteEnd - characterSelState.absoluteStart;
(SelManager as IEditManager).deleteNextCharacter();
checkExpectedSelection(initialSelection, initialSelection);
assertTrue("deleteNextCharacterTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - characterLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
assertTrue("deleteNextCharacterTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(initialSelection, initialSelection);
assertTrue("deleteNextCharacterTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - characterLength);
}
/** Test backspace from a caret position */
public function deletePreviousCharacterTest():void
{
const initialSelection:int = 10;
var flowLength:int = SelManager.textFlow.textLength;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelection, initialSelection);
var originalSelectionState:SelectionState = SelManager.getSelectionState();
var characterSelState:SelectionState = SelManager.getSelectionState();
NavigationUtil.nextCharacter(characterSelState,true);
var characterLength:int = characterSelState.absoluteEnd - characterSelState.absoluteStart;
(SelManager as IEditManager).deletePreviousCharacter();
checkExpectedSelection(initialSelection - characterLength, initialSelection - characterLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after deletion by word", SelManager.textFlow.textLength == flowLength - characterLength);
// After undo, selection returns to original state
checkUndo(originalSelectionState.absoluteStart, originalSelectionState.absoluteEnd);
// checkUndo(initialSelection, initialSelection + characterLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after undo of deletion by word", SelManager.textFlow.textLength == flowLength);
// After redo, caret selection should be restored to original state
checkRedo(initialSelection - characterLength, initialSelection - characterLength);
assertTrue("deleteNextWordTest: TextFlow length not as expected after redo of deletion by word", SelManager.textFlow.textLength == flowLength - characterLength);
}
public function applyCharacterFormatSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
var characterFormat:TextLayoutFormat = new TextLayoutFormat();
characterFormat.color = 0xFF0000;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).applyLeafFormat(characterFormat);
checkExpectedSelection(initialSelectionStart, initialSelectionEnd);
// After undo, inserted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionStart, initialSelectionEnd);
}
public function applyParagraphFormatSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat();
paragraphFormat.paragraphStartIndent = 15;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).applyParagraphFormat(paragraphFormat);
checkExpectedSelection(initialSelectionStart, initialSelectionEnd);
// After undo, inserted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionStart, initialSelectionEnd);
}
public function applyContainerFormatSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
var containerFormat:TextLayoutFormat = new TextLayoutFormat();
containerFormat.paddingLeft = 15;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).applyContainerFormat(containerFormat);
checkExpectedSelection(initialSelectionStart, initialSelectionEnd);
// After undo, inserted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionStart, initialSelectionEnd);
}
public function applyLinkSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).applyLink("http://www.cnn.com");
checkExpectedSelection(initialSelectionStart, initialSelectionEnd);
// After undo, inserted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionStart, initialSelectionEnd);
}
public function applyTCYSelectionTest():void
{
const initialSelectionStart:int = 10;
const initialSelectionEnd:int = 20;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionStart, initialSelectionEnd);
(SelManager as IEditManager).applyTCY(true);
checkExpectedSelection(initialSelectionStart, initialSelectionEnd);
// After undo, inserted text should be selected
checkUndo(initialSelectionStart, initialSelectionEnd);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionStart, initialSelectionEnd);
}
public function insertInlineGraphicSelectionTest():void
{
const initialSelectionPosition:int = 10;
// Try a caret selection. After do, selection should be a caret point following the inserted text
SelManager.selectRange(initialSelectionPosition, initialSelectionPosition);
(SelManager as IEditManager).insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseURL,"../../test/testFiles/assets/surprised.png"), Number(10), Number(10));
checkExpectedSelection(initialSelectionPosition + 1, initialSelectionPosition + 1);
// After undo, inserted text should be selected
checkUndo(initialSelectionPosition, initialSelectionPosition);
// After redo, caret selection should be restored to after the inserted text
checkRedo(initialSelectionPosition + 1, initialSelectionPosition + 1);
}
public function copyAndPasteSelectionTest():void
{
const copyStart:int = 10;
const copyEnd:int = 14;
const pastePosition:int = 20;
var pasteLength:int = copyEnd - copyStart;
SelManager.selectRange(copyStart, copyEnd);
var scrap:TextScrap = TextScrap.createTextScrap(SelManager.getSelectionState());
var flowLength:int = SelManager.textFlow.textLength;
var markup:XML = new XML(TextClipboard.exportForClipboard(scrap, TextConverter.TEXT_LAYOUT_FORMAT));
assertTrue("Get the expected string from clipboard", markup..*::p..*::span == TextClipboard.exportForClipboard(scrap, TextConverter.PLAIN_TEXT_FORMAT));
SelManager.selectRange(pastePosition, pastePosition);
(SelManager as IEditManager).pasteTextScrap(scrap);
checkExpectedSelection(pastePosition + pasteLength, pastePosition + pasteLength);
var resultString:String = TestFrame.textFlow.getCharAtPosition(20) + TestFrame.textFlow.getCharAtPosition(21) +
TestFrame.textFlow.getCharAtPosition(22) + TestFrame.textFlow.getCharAtPosition(23);
assertTrue("Paste the exact string from clipboard", resultString == TextClipboard.exportForClipboard(scrap, TextConverter.PLAIN_TEXT_FORMAT));
assertTrue("Paste found unexpected textFlow length, was expecting " + flowLength + pasteLength + " actual " + SelManager.textFlow.textLength,
SelManager.textFlow.textLength == flowLength + pasteLength );
checkUndo(pastePosition, pastePosition);
assertTrue("Paste undo, textFlow not set back to original size ", SelManager.textFlow.textLength == flowLength);
checkRedo(pastePosition + pasteLength, pastePosition + pasteLength);
assertTrue("Paste redo, textFlow not set back to pasted size ", SelManager.textFlow.textLength == flowLength + pasteLength);
if (Configuration.playerEnablesArgoFeatures)
System["disposeXML"](markup);
}
public function cutAndPasteSelectionTest():void
{
cutAndPasteSelectionCaret();
cutAndPasteSelectionRange();
}
public function cutAndPasteSelectionCaret():void
{
const cutStart:int = 10;
const cutEnd:int = 20;
const pastePosition:int = 10;
var pasteLength:int = cutEnd - cutStart;
// Paste into a point selection
SelManager.selectRange(cutStart, cutEnd);
var scrap:TextScrap = SelManager.cutTextScrap();
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(pastePosition, pastePosition);
(SelManager as IEditManager).pasteTextScrap(scrap);
checkExpectedSelection(pastePosition + pasteLength, pastePosition + pasteLength);
assertTrue("Paste found unexpected textFlow length, was expecting " + flowLength + pasteLength + " actual " + SelManager.textFlow.textLength,
SelManager.textFlow.textLength == flowLength + pasteLength);
checkUndo(pastePosition, pastePosition);
assertTrue("Paste undo, textFlow not set back to original size ", SelManager.textFlow.textLength == flowLength);
checkRedo(pastePosition + pasteLength, pastePosition + pasteLength);
assertTrue("Paste redo, textFlow not set back to pasted size ", SelManager.textFlow.textLength == flowLength + pasteLength);
}
public function cutAndPasteSelectionRange():void
{
const cutStart:int = 10;
const cutEnd:int = 20;
const pastePosition:int = 10;
var pasteLength:int = cutEnd - cutStart;
// Paste into a point selection
SelManager.selectRange(cutStart, cutEnd);
var scrap:TextScrap = SelManager.cutTextScrap();
var flowLength:int = SelManager.textFlow.textLength;
const amtToDelete:int = 10;
SelManager.selectRange(pastePosition, pastePosition + amtToDelete);
(SelManager as IEditManager).pasteTextScrap(scrap);
checkExpectedSelection(pastePosition + pasteLength, pastePosition + pasteLength);
assertTrue("Paste found unexpected textFlow length, was expecting " + (flowLength + pasteLength - amtToDelete).toString + " actual " + SelManager.textFlow.textLength,
SelManager.textFlow.textLength == flowLength + pasteLength - amtToDelete);
checkUndo(pastePosition, pastePosition + amtToDelete);
assertTrue("Paste undo, textFlow not set back to original size ", SelManager.textFlow.textLength == flowLength);
checkRedo(pastePosition + pasteLength, pastePosition + pasteLength);
assertTrue("Paste redo, textFlow not set back to pasted size ", SelManager.textFlow.textLength == flowLength + pasteLength - amtToDelete);
}
public function limitPasteTest(callback:Object = null):void
{
const pastePosition:int = 10;
const maxFlowLength:int = 10552;
if(!callback)
{
callback = true;
const cutStart:int = 10;
const cutEnd:int = 20;
var pasteLength:int = cutEnd - cutStart;
// Paste into a point selection
SelManager.selectRange(cutStart, cutEnd);
var scrap:TextScrap = SelManager.cutTextScrap();
SelManager.textFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_END,limitPasteTest,false,0,true);
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(pastePosition, pastePosition);
(SelManager as IEditManager).pasteTextScrap(scrap);
var afterDoLength:int = SelManager.textFlow.textLength;
assertTrue("pasted too much", SelManager.textFlow.textLength <= maxFlowLength);
(SelManager as IEditManager).undo();
assertTrue("unexpected text Length after undo, was expecting " + flowLength.toString() + "got " + SelManager.textFlow.textLength.toString(), SelManager.textFlow.textLength == flowLength);
(SelManager as IEditManager).redo();
assertTrue("unexpected text length after redo", SelManager.textFlow.textLength == afterDoLength);
}
else
{
SelManager.textFlow.removeEventListener(FlowOperationEvent.FLOW_OPERATION_END,limitPasteTest);
var operation:PasteOperation = (callback is FlowOperationEvent) ? FlowOperationEvent(callback).operation as PasteOperation : null;
if (operation && SelManager.textFlow.textLength > maxFlowLength)
{
var trimAmt:int = SelManager.textFlow.textLength - maxFlowLength;
var pasteEnd:int = pastePosition + (operation.absoluteEnd - operation.absoluteStart);
SelManager.selectRange(pasteEnd - trimAmt, pasteEnd);
(SelManager as IEditManager).deleteNextCharacter();
}
}
}
public function deleteNextCharExceptionTest(callback:Object = null):void
{
var gotException:Boolean = false;
const pastePosition:int = 10;
if(!callback)
{
callback = true;
const cutStart:int = 10;
const cutEnd:int = 20;
var pasteLength:int = cutEnd - cutStart;
// Paste into a point selection
SelManager.selectRange(cutStart, cutEnd);
var scrap:TextScrap = SelManager.cutTextScrap();
SelManager.textFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_END,deleteNextCharExceptionTest,false,0,true);
var flowLength:int = SelManager.textFlow.textLength;
SelManager.selectRange(pastePosition, pastePosition);
(SelManager as IEditManager).pasteTextScrap(scrap);
}
else
{
SelManager.textFlow.removeEventListener(FlowOperationEvent.FLOW_OPERATION_END,deleteNextCharExceptionTest);
var operation:PasteOperation = (callback is FlowOperationEvent) ? FlowOperationEvent(callback).operation as PasteOperation : null;
if (operation)
{
try
{
(SelManager as IEditManager).deleteNextCharacter();
}
catch (e:Error)
{
// EditManager used to remap the error when deleteNextCharacter was working on an INVALID TextBlock
// This was silly - there's lots of other conditiosn this can happen - deleteNextWord etc.
// Changed so that the error just goes through. Besides the "remapped" error doesn't really help users now does it.
gotException = e is IllegalOperationError;
}
finally
{
// This assertion when it fires causes VellumUnit to halt with a posted error - its not caught by FlexUnit. That's ugly.
assertTrue("Expected special exception for deleting from a caret selection on damaged text", gotException);
}
}
}
}
public function cancelSplitParagraphTest(callback:Object = null):void
{
if(!callback)
{
callback = true;
SelManager.textFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_BEGIN,cancelSplitParagraphTest,false,0,true);
// Paste into a point selection
SelManager.selectRange(0, 0);
(SelManager as IEditManager).insertText("h");
(SelManager as IEditManager).insertText("e");
(SelManager as IEditManager).insertText("l");
(SelManager as IEditManager).insertText("l");
(SelManager as IEditManager).insertText("o");
(SelManager as IEditManager).splitParagraph();
}
else
{
var operation:SplitParagraphOperation = (callback is FlowOperationEvent) ? FlowOperationEvent(callback).operation as SplitParagraphOperation : null;
if (operation && operation.absoluteStart == 0)
{
SelManager.textFlow.removeEventListener(FlowOperationEvent.FLOW_OPERATION_BEGIN,cancelSplitParagraphTest);
FlowOperationEvent(callback).preventDefault();
SelManager.selectRange(0, 0);
}
}
}
public function cancelCopyOperationTest(callback:Object = null):void
{
var cancelCalled:Boolean = false;
function cancelCopyOperation(e:FlowOperationEvent):void
{ e.preventDefault(); cancelCalled = true; }
SelManager.textFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_BEGIN,cancelCopyOperation);
SelManager.editHandler(new Event(Event.COPY));
assertTrue("cancelCopyOperationTest expect cancel to be called",cancelCalled);
}
public function compositeOperationTest():void
{
var editManager:IEditManager = SelManager as IEditManager;
var insertPos:int = 15;
var insertText:String = "Hello There";
var insertSize:Number = 48;
var originalSize:Number = Number(SelManager.textFlow.findLeaf(insertPos).computedFormat.fontSize);
var flowLength:int = SelManager.textFlow.textLength;
editManager.beginCompositeOperation();
SelManager.selectRange(insertPos, insertPos);
editManager.insertText(insertText);
SelManager.selectRange(insertPos, insertPos + insertText.length);
var charFormat:TextLayoutFormat = new TextLayoutFormat();
charFormat.fontSize = insertSize;
editManager.applyFormat(charFormat,null,null);
editManager.endCompositeOperation();
assertTrue("Point size not as expected", Number(SelManager.textFlow.findLeaf(insertPos).computedFormat.fontSize) == insertSize);
assertTrue("TextFlow length not as expected", SelManager.textFlow.textLength == flowLength + insertText.length);
// State after a single undo should be back to original at start of function
editManager.undo();
assertTrue("Point size not as expected", Number(SelManager.textFlow.findLeaf(insertPos).computedFormat.fontSize) == originalSize);
assertTrue("TextFlow length not as expected", SelManager.textFlow.textLength == flowLength);
// State after a single redo should be back to after operation done
editManager.redo();
assertTrue("Point size not as expected", Number(SelManager.textFlow.findLeaf(insertPos).computedFormat.fontSize) == insertSize);
assertTrue("TextFlow length not as expected", SelManager.textFlow.textLength == flowLength + insertText.length);
}
// Compare the selected text to the keystring, and assert if they are different
private function checkSelectedText(keyString:String):void
{
var leaf:FlowLeafElement = SelManager.textFlow.findLeaf(SelManager.absoluteStart);
var compareString:String = leaf.text.substr(SelManager.absoluteStart - leaf.getAbsoluteStart(), keyString.length);
assertTrue ("Selected text doesn't match expected", compareString == keyString);
}
// Test operations that don't apply to the selection, and make sure selection is maintained across the operations
public function programmaticOperationTest():void
{
var editManager:IEditManager = SelManager as IEditManager;
// Test selection after the change
const initialSelectionStart:int = 100;
var keyString:String = "Hello there";
// Insert text with no selection
editManager.insertText(keyString, new SelectionState(editManager.textFlow, initialSelectionStart, initialSelectionStart));
editManager.flushPendingOperations();
// Set the selection to the text we just inserted
SelManager.selectRange(initialSelectionStart, initialSelectionStart + keyString.length);
checkSelectedText(keyString);
// Insert a string right before
editManager.insertText("ABC", new SelectionState(editManager.textFlow, initialSelectionStart, initialSelectionStart));
editManager.flushPendingOperations();
checkSelectedText(keyString);
// Delete a string right before
editManager.deleteNextCharacter(new SelectionState(editManager.textFlow, initialSelectionStart, initialSelectionStart + 3));
checkSelectedText(keyString);
// Insert a string right after
editManager.insertText("ABC", new SelectionState(editManager.textFlow, initialSelectionStart + keyString.length, initialSelectionStart + keyString.length));
editManager.flushPendingOperations();
checkSelectedText(keyString);
// Delete a string right after
editManager.deleteNextCharacter(new SelectionState(editManager.textFlow, initialSelectionStart + keyString.length, initialSelectionStart + keyString.length + 3));
checkSelectedText(keyString);
}
public function deleteLastSpanTest():void
{
var indx:int = 50;
var width:int = 20;
var height:int = 20;
SelManager.selectRange(indx, indx);
SelManager.insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseURL,"../../test/testFiles/assets/smiling.png"),width,height);
var origFlowLength:int = SelManager.textFlow.textLength;
var amtToDelete:int = SelManager.textFlow.textLength - (indx + 1) - 1; // Carriage return at the end not deleted
SelManager.selectRange(indx + 1, SelManager.textFlow.textLength);
(SelManager as EditManager).deleteNextCharacter();
assertTrue("Unexpected length after delete", SelManager.textFlow.textLength == origFlowLength - amtToDelete);
(SelManager as EditManager).undo();
assertTrue("Unexpected length after undo delete", SelManager.textFlow.textLength == origFlowLength);
(SelManager as EditManager).redo();
assertTrue("Unexpected length after redo delete", SelManager.textFlow.textLength == origFlowLength - amtToDelete);
}
public function mergeEventMirrorTest( e:Event = null ):void
{
if ( e != null )
return;
SelManager.selectAll();
SelManager.deleteText();
var p:ParagraphElement = new ParagraphElement();
var span1:SpanElement = new SpanElement();
span1.text = "A";
var span2:SpanElement = new SpanElement();
span2.text = "B";
// This should cause the spans not to merge - Event.FULLSCREEN was chosen at random
// It is not enough to have a single mirror - both span elements need to
// have active mirrors
span1.getEventMirror().addEventListener( Event.FULLSCREEN, mergeEventMirrorTest );
span2.getEventMirror().addEventListener( Event.FULLSCREEN, mergeEventMirrorTest );
p.addChild(span1);
p.addChild(span2);
TestFrame.textFlow.addChild(p);
TestFrame.textFlow.flowComposer.updateAllControllers();
assertTrue( "Spans should not merge if an active event listener is attached to both", p.numChildren == 2 );
span1.getEventMirror().removeEventListener( Event.FULLSCREEN, mergeEventMirrorTest );
span2.getEventMirror().removeEventListener( Event.FULLSCREEN, mergeEventMirrorTest );
TestFrame.textFlow.flowComposer.updateAllControllers();
}
public function applyLeafFormatTest():void
{
// Applying a leaf format to an empty paragraph should apply immediately to the paragraph
var textFlow:TextFlow = SelManager.textFlow;
SelManager.selectRange(textFlow.textLength - 1, textFlow.textLength - 1);
SelManager.splitParagraph();
SelManager.selectRange(textFlow.textLength - 1, textFlow.textLength - 1);
var newSize:int = textFlow.getLastLeaf().computedFormat.fontSize + 10;
var leafFormat:TextLayoutFormat = new TextLayoutFormat();
leafFormat.fontSize = newSize;
SelManager.applyLeafFormat(leafFormat);
assertTrue("Expected point size change to be applied immediately to empty paragraph", textFlow.getLastLeaf().computedFormat.fontSize == newSize);
// Applying a leaf format to a paragraph with content should not change the paragraph,
// but should change the pointFormat.
SelManager.selectRange(0, 0);
var originalSize:int = textFlow.getFirstLeaf().computedFormat.fontSize;
newSize = originalSize + 10;
leafFormat = new TextLayoutFormat();
leafFormat.fontSize = newSize;
SelManager.applyLeafFormat(leafFormat);
assertTrue("Expected point size change to be delayed", textFlow.getFirstLeaf().computedFormat.fontSize == originalSize);
SelManager.allowDelayedOperations = false;
SelManager.insertText("X");
assertTrue("Expected point size change to be applied to newly inserted text", textFlow.getFirstLeaf().computedFormat.fontSize == newSize);
// Applying a leaf format to a para with content, followed by applying to an empty paragraph, should result in inserted text in the font of the second apply
// Watson 2791491
SelManager.selectRange(0, textFlow.textLength - 1);
SelManager.deleteText();
leafFormat = new TextLayoutFormat();
leafFormat.fontFamily = "Courier";
SelManager.applyLeafFormat(leafFormat);
SelManager.insertText("A");
assertTrue("Expected fontFamily change to be applied to newly inserted text", textFlow.getFirstLeaf().computedFormat.fontFamily == "Courier");
SelManager.selectRange(0, textFlow.textLength - 1);
SelManager.deleteText();
leafFormat.fontFamily = "Verdana";
SelManager.applyLeafFormat(leafFormat);
SelManager.insertText("B");
assertTrue("Expected fontFamily change to be applied to newly inserted text", textFlow.getFirstLeaf().computedFormat.fontFamily == "Verdana");
}
public function undoApplyFormatToElementTest():void
{
// Test for scenario in Watson bug# 2315405
var textFlow:TextFlow = SelManager.textFlow;
var format:TextLayoutFormat = new TextLayoutFormat();
format.color = 0xff; // character category
format.leadingModel = LeadingModel.ASCENT_DESCENT_UP; // paragraph category
format.columnCount = 2; // container category
var beforeFormat:ITextLayoutFormat = textFlow.format ? textFlow.format : TextLayoutFormat.emptyTextLayoutFormat;
SelManager.applyFormatToElement(textFlow, format);
assertTrue( "applyFormatToElement did not work", textFlow.color == format.color);
assertTrue( "applyFormatToElement did not work", textFlow.leadingModel == format.leadingModel);
assertTrue( "applyFormatToElement did not work", textFlow.columnCount == format.columnCount);
SelManager.undo();
assertTrue( "undo applyFormatToElement did not work", textFlow.color === beforeFormat.color);
assertTrue( "undo applyFormatToElement did not work", textFlow.leadingModel === beforeFormat.leadingModel);
assertTrue( "undo applyFormatToElement did not work", textFlow.columnCount === beforeFormat.columnCount);
}
// Test for scenario in Watson bug# 2366728
public function applyFormatToElementTest():void
{
var textFlow:TextFlow = SelManager.textFlow;
var format1:TextLayoutFormat = new TextLayoutFormat();
format1.color = 0xff;
format1.fontSize = 30;
var elem1:FlowElement = SelManager.textFlow.findLeaf(1);
SelManager.applyFormatToElement(elem1, format1);
var elem2:FlowElement = SelManager.textFlow.findLeaf(30);
var format2:TextLayoutFormat = new TextLayoutFormat();
format2.color = elem2.color;
format2.fontSize = elem2.fontSize;
assertTrue("applyFormatToElement ignores targetElements and applies changes to the TextFlow. ",
format1.color != format2.color && format1.fontSize != format2.fontSize );
}
public function clearFormatOnElementTest():void
{
var format1:TextLayoutFormat = new TextLayoutFormat();
format1.color = 0xff;
format1.fontSize = 30;
var para:FlowElement = SelManager.textFlow.getFirstLeaf().getParagraph();
SelManager.applyFormatToElement(para, format1);
assertTrue("clearFormatOnElementTest failed to apply formats. ",
para.color == format1.color && para.fontSize == format1.fontSize );
// now lets undefine them
SelManager.clearFormatOnElement(para,format1);
assertTrue("clearFormatOnElementTest failed to undefine formats. ",
para.color === undefined && para.fontSize === undefined );
}
private function changeOperationTestEventListener(event:FlowOperationEvent):void
{
event.operation.textFlow.removeEventListener(FlowOperationEvent.FLOW_OPERATION_BEGIN,changeOperationTestEventListener);
event.operation = new DeleteTextOperation(SelManager.getSelectionState());
}
/** Change the operation in the flowOperationBegin event handler */
public function changeOperationTest():void
{
SelManager.selectAll();
SelManager.textFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_BEGIN,changeOperationTestEventListener);
// start out changing the fontSize
var format:TextLayoutFormat = new TextLayoutFormat();
format.fontSize = 88;
SelManager.applyLeafFormat(format);
assertTrue("changeOperationTest failed to delete text.", SelManager.textFlow.textLength == 1);
}
public function pendingFlushTest():void
{
SelManager.selectRange(0,0);
var beforeLen:int = SelManager.textFlow.textLength;
SelManager.insertText("XYZ ");
SelManager.deletePreviousWord();
SelManager.flushPendingOperations();
var afterLen:int = SelManager.textFlow.textLength;
assertTrue("pending operation wasn't flushed before deletePreviousWord", beforeLen == afterLen);
// textflow should just have XYZ after this
SelManager.selectRange(0,0);
var operationState:SelectionState = new SelectionState(SelManager.textFlow,0,SelManager.textFlow.textLength-1);
SelManager.insertText("XYZ");
SelManager.deleteText(operationState);
var para:ParagraphElement = SelManager.textFlow.getFirstLeaf().getParagraph();
var paraText:String = para.getText(0,-1,"");
assertTrue("Incorrect textFlow in pendingFlushTest",SelManager.textFlow.textLength == 4 && paraText == "XYZ");
}
private var eventCount:int;
private var expectedEvents:Array;
// verifies that events are recieved in the order expected
private function catchEvent(e:Event):void
{
var expected:Object = expectedEvents[eventCount++];
assertTrue("Unexpected event caught",e.type);
assertTrue("Unexecpted event type",e.type == expected.name);
if (e is FlowOperationEvent)
{
assertTrue("Unexpected level",FlowOperationEvent(e).level == expected.level);
var className:String = flash.utils.getQualifiedClassName(FlowOperationEvent(e).operation);
var baseClassName:String = className.substr(className.lastIndexOf(":")+1);
assertTrue("Unexpected operation class name",baseClassName == expected.operation);
}
}
public function compositeOperationEventTest():void
{
eventCount = 0;
// events in order they are expected
expectedEvents = [
{name:"flowOperationBegin",level:0,operation:"CompositeOperation"},
{name:"flowOperationBegin",level:1,operation:"CompositeOperation"},
{name:"flowOperationBegin",level:2,operation:"InsertTextOperation"},
{name:"flowOperationEnd",level:2,operation:"InsertTextOperation"},
{name:"flowOperationBegin",level:2,operation:"InsertTextOperation"},
{name:"flowOperationEnd",level:2,operation:"InsertTextOperation"},
{name:"flowOperationEnd",level:1,operation:"CompositeOperation"},
{name:"flowOperationBegin",level:1,operation:"ApplyFormatOperation"},
{name:"flowOperationEnd",level:1,operation:"ApplyFormatOperation"},
{name:"flowOperationEnd",level:0,operation:"CompositeOperation"},
{name:"compositionComplete"},
{name:"updateComplete"},
{name:"flowOperationComplete",level:0,operation:"CompositeOperation"} ];
var eventsToCatch:Array = [
FlowOperationEvent.FLOW_OPERATION_BEGIN,
FlowOperationEvent.FLOW_OPERATION_END,
FlowOperationEvent.FLOW_OPERATION_COMPLETE,
CompositionCompleteEvent.COMPOSITION_COMPLETE,
UpdateCompleteEvent.UPDATE_COMPLETE
];
var textFlow:TextFlow = SelManager.textFlow;
var eventName:String;
for each(eventName in eventsToCatch)
textFlow.addEventListener(eventName,catchEvent);
SelManager.beginCompositeOperation();
SelManager.beginCompositeOperation();
SelManager.selectRange(int.MAX_VALUE, int.MAX_VALUE);
SelManager.insertText(" wor");
SelManager.insertText("ld");
SelManager.endCompositeOperation();
SelManager.selectAll();
var newLeafFormat:TextLayoutFormat = new TextLayoutFormat();
newLeafFormat.color = 0xff;
SelManager.applyFormat(newLeafFormat,null,null);
SelManager.endCompositeOperation();
assertTrue("Events missing",eventCount == expectedEvents.length);
for each(eventName in eventsToCatch)
textFlow.removeEventListener(eventName,catchEvent);
}
public function delayedRedrawTest():void
// Test EditManager.delayUpdates flag. When set, calls on the EditManager should update the model,
// but not recompose or update the view. When clear, calls on the EditManager should synchronously
// recompose and update.
{
var textFlow:TextFlow = SelManager.textFlow;
var flowComposer:IFlowComposer = textFlow.flowComposer;
var editManager:EditManager = textFlow.interactionManager as EditManager;
var container:Sprite = SelManager.textFlow.flowComposer.getControllerAt(0).container;
var originalRedrawSetting:Boolean = editManager.delayUpdates;
try
{
// Turn delayUpdates on, make a change. The model should be updated, but the text
// should not be recomposed and the container display list should not be touched.
editManager.delayUpdates = true;
SelManager.selectRange(0, int.MAX_VALUE);
flowComposer.updateAllControllers(); // force lines to be generated
EditManager(SelManager).deleteText();
assertTrue("textFlow deletion not done?", textFlow.textLength <= 1);
assertTrue("textFlow composition wasn't delayed?", flowComposer.getLineAt(0).validity == TextLineValidity.INVALID);
assertTrue("textFlow update wasn't delayed?", container.numChildren > 2);
// Force an update. After this, text should be recomposed, and display list updated.
EditManager(SelManager).updateAllControllers();
assertTrue("textFlow composition wasn't delayed?", flowComposer.numLines <= 1);
assertTrue("textFlow update wasn't delayed?", container.numChildren == 2); // one for selection shape, one for empty line
// Turn delayUpdates off, then undo. The model should be updated, the text should be
// recomposed and the container should be updated.
editManager.delayUpdates = false;
EditManager(SelManager).undo();
assertTrue("textFlow undo of deletion not done?", textFlow.textLength > 1);
assertTrue("textFlow composition was delayed after undo?", flowComposer.numLines > 1);
assertTrue("textFlow composition was delayed?", flowComposer.getLineAt(0).validity == TextLineValidity.VALID);
assertTrue("textFlow update was delayed after undo?", container.numChildren > 2);
// Turn delayUpdates on, then edit, then switch to read-only mode. Watson 2765114
editManager.delayUpdates = true;
editManager.selectRange(0, 0);
editManager.insertText("hello there");
// 2793943 - delayUpdates on TextFlow with no controllers
var textFlowNoController:TextFlow = textFlow.deepCopy() as TextFlow;
var emNoController:EditManager = new EditManager();
textFlowNoController.interactionManager = emNoController;
emNoController.allowDelayedOperations = false;
emNoController.delayUpdates = true;
emNoController.selectRange(0, 0);
emNoController.insertText("hello");
textFlowNoController.flowComposer.updateAllControllers();
// test for
var extraEditmanager:EditManager = new EditManager();
var testEditManager:EditManager = new EditManager();
assertTrue("EditManager delayUpdates by default should be false", testEditManager.delayUpdates == false);
testEditManager.delayUpdates = true;
assertTrue("EditManager delayUpdates by default should be false", extraEditmanager.delayUpdates == false);
textFlow.interactionManager = new SelectionManager();
SelManager = null; // avoid tearDown assert for inactive SelectionManager
}
finally
{
editManager.delayUpdates = originalRedrawSetting;
}
}
public function delayUpdateNoFlowComposer(callBack:Object = null):void // 2785924
{
if (!callBack)
{
// test for 2785924
var textFlow:TextFlow = TextConverter.importToFlow("Hello world", TextConverter.PLAIN_TEXT_FORMAT);
textFlow.flowComposer.addController(new ContainerController(new Sprite(), 200, 300));
var editManager:EditManager = new EditManager();
editManager.delayUpdates = true;
textFlow.interactionManager = editManager;
textFlow.flowComposer.updateAllControllers();
editManager.selectRange(0, textFlow.textLength);
var leafFormat:TextLayoutFormat = new TextLayoutFormat();
leafFormat.fontSize = 60;
editManager.applyLeafFormat(leafFormat);
textFlow.flowComposer = null;
var delay:Boolean = true;
TestFrame.container.addEventListener(Event.ENTER_FRAME, addAsync(delayUpdateNoFlowComposer,2500,null),false,0,true);
}
else
{
}
}
public function allowDelayedOperations():void
{
// When delayed operations are turned off, insertion should happen immediately
SelManager.selectRange(0, 0);
SelManager.allowDelayedOperations = false;
var originalTextLength:int = SelManager.textFlow.textLength;
SelManager.insertText("A");
assertTrue("Expected immediate insertion", SelManager.textFlow.textLength > originalTextLength);
// When delayed operations are turned on, insertion should NOT happen immediately, but should happen after flush
SelManager.allowDelayedOperations = true;
originalTextLength = SelManager.textFlow.textLength;
SelManager.insertText("A");
assertTrue("Expected delayed insertion", SelManager.textFlow.textLength == originalTextLength);
SelManager.flushPendingOperations();
assertTrue("Expected insertion after flush", SelManager.textFlow.textLength > originalTextLength);
// If an operation is queued up, and allowDelayedOperations is turned off, it should get flushed
originalTextLength = SelManager.textFlow.textLength;
SelManager.insertText("A");
assertTrue("Expected delayed insertion (2)", SelManager.textFlow.textLength == originalTextLength);
SelManager.allowDelayedOperations = false;
assertTrue("Expected insertion after allowDelayedOperations turned off", SelManager.textFlow.textLength > originalTextLength);
}
public function undoApplyParagraphFormat():void
// Apply a paragraph format to an empty paragraph, and undo. Should get back to the original state. Watson 2629735
{
var textFlow:TextFlow = SelManager.textFlow;
SelManager.selectRange(0, textFlow.textLength);
SelManager.deleteText();
SelManager.selectRange(0, 0);
var format:TextLayoutFormat = new TextLayoutFormat();
format.paragraphStartIndent = 25; // give it some initial value so we don't have to check for undefined
SelManager.applyParagraphFormat(format);
// Save off original value
var leaf:FlowLeafElement = textFlow.findLeaf(0);
var para:ParagraphElement = leaf.getParagraph();
var indent:Number = para.format.paragraphStartIndent;
format = new TextLayoutFormat();
format.paragraphStartIndent = indent + 25;
SelManager.applyParagraphFormat(format);
SelManager.undo();
leaf = textFlow.findLeaf(0);
para = leaf.getParagraph();
assertTrue("Expected original value back in paragraph format after undo", para.format.paragraphStartIndent == indent);
}
private function undoHelper(markup:String, startPos:int, endPos:int, doFunction:Function, expectedResult:String = null):void
{
var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT);
var originalMarkup:String = TextConverter.export(textFlow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.STRING_TYPE) as String;
testApp.contentChange(textFlow);
var editManager:IEditManager = (textFlow.interactionManager as IEditManager);
textFlow.interactionManager.selectRange(startPos,endPos);
var selectAnchorPosition:int = textFlow.interactionManager.anchorPosition;
var selectActivePosition:int = textFlow.interactionManager.activePosition;
doFunction(textFlow);
var afterDoMarkup:String = TextConverter.export(textFlow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.STRING_TYPE) as String;
var afterDoAnchorPos:int = textFlow.interactionManager.anchorPosition;
var afterDoActivePos:int = textFlow.interactionManager.activePosition;
assertTrue("expected undoable operation on the stack", editManager.undoManager.canUndo());
if (expectedResult)
{
if (afterDoMarkup != expectedResult)
{
trace(afterDoMarkup);
trace(expectedResult);
}
assertTrue("Actual result after edit doesn't match expected result", afterDoMarkup == expectedResult);
}
editManager.undo();
var afterUndoAnchorPos:int = textFlow.interactionManager.anchorPosition;
var afterUndoActivePos:int = textFlow.interactionManager.activePosition;
var afterUndoMarkup:String = TextConverter.export(textFlow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.STRING_TYPE) as String;
assertTrue("Didn't get back to original model state after undo", afterUndoMarkup == originalMarkup);
assertTrue("Didn't return selection to original state after undo", afterUndoAnchorPos == selectAnchorPosition && afterUndoActivePos == selectActivePosition);
editManager.redo();
var afterRedoAnchorPos:int = textFlow.interactionManager.anchorPosition;
var afterRedoActivePos:int = textFlow.interactionManager.activePosition;
var afterRedoMarkup:String = TextConverter.export(textFlow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.STRING_TYPE) as String;
assertTrue("Didn't get back to post-Do model state after redo", afterRedoMarkup == afterDoMarkup);
assertTrue("Didn't return selection to original state after redo", afterRedoAnchorPos == afterDoAnchorPos && afterRedoActivePos == afterDoActivePos);
}
public function undoDelete():void
{
undoHelper(' para1 para2 para3 [1] [35[36 [37 BEF ite ano ite ano ano ano ano ano ano ano ano ano ite ano AFT BEF ite ano ite ano ano ano ano ano ano ano ano ano ite ano AFT BEF ite ano ite ano ano ano ano ano ano ano ano ano ite ano AFT BEF ite ano ite ano ano ano ano ano ano ano ano ano ite ano AFT BEF ite ano ite ano ano ano ano ano ano ano ano ano ite ano AFT Thesuc li The Thesuc li The Thesuc li The Thesuc li The There are many such lime-kilns in that tract of country, for the purpose of burning the white marble which composes a large part of the substance of the hills. Some of them, built years ago, and long deserted, with weeds growing in the vacant round of the interior, which is open to the sky, and grass and wild-flowers rooting themselves into the chinks of the stones, look already like relics of antiquity, and may yet be overspread with the lichens of centuries to come. Others, where the lime-burner still feeds his daily and nightlong fire, afford points of interest to the wanderer among the hills, who seats himself on a log of wood or a fragment of marble, to hold a chat with the solitary man. It is a lonesome, and, when the character is inclined to thought, may be an intensely thoughtful occupation; as it proved in the case of Ethan Brand, who had mused to such strange purpose, in days gone by, while the fire in this very kiln was burning. The man who now watched the fire was of a different order, and troubled himself with no thoughts save the very few that were requisite to his business. At frequent intervals, he flung back the clashing weight of the iron door, and, turning his face from the insufferable glare, thrust in huge logs of oak, or stirred the immense brands with a long pole. Within the furnace were seen the curling and riotous flames, and the burning marble, almost molten with the intensity of heat; while without, the reflection of the fire quivered on the dark intricacy of the surrounding forest, and showed in the foreground a bright and ruddy little picture of the hut, the spring beside its door, the athletic and coal-begrimed figure of the lime-burner, and the half-frightened child, shrinking into the protection of his fathers shadow. And when again the iron door was closed, then reappeared the tender light of the half-full moon, which vainly strove to trace out the indistinct shapes of the neighboring mountains; and, in the upper sky, there was a flitting congregation of clouds, still faintly tinged with the rosy sunset, though thus far down into the valley the sunshine had vanished long and long ago. test AAA BBB CCC DDD
AAA
BBB
CCC
DDD
AAA
BBB
CCC
DDD
AAA
BBB
CCC
DDD
Thesuc li
The
Thesuc li
The
Thesuc li
The
Thesuc li
The
Thesuc li
The
ab
cd
one
two
three
four
one
two
three
Thesuc li
The
a
b
a
b
Filler
Before list
a
b
Filler
B
Thesuc li
The
Thesuc li
The
Thesuc lim
The
Bar
The
The
ab
cd
Thesuc lim
The
here >< more
onetwo
' + 'threefourLink
Xonetwo
' + 'threefourLink
oneXtwo
' + 'threefourLink
onetwoX
' + 'threefourLink
onetXwo
' + 'threefourLink
onet
threefourLink
onetXwo
' + 'threefourLink
onetwo
' + 'threefourLink
onetwo
' + 'threefourLink
onetwo
' + 'threefourXLink
onetwo
' + 'threefourLinkX
onetwo
' + 'threefour
onetwo
' + 'threefourX
onetwo
' + 'threefour
onetwo
' + 'threefour
onetwo
' + 'threefour
onetwo
' + 'threefour
ABCDX
onetwo
' + 'threefour
onetwo
' + 'threefourX
onetwo
' + 'threefour
onetwo
' + 'threefour
onetwo
' + 'threefour
onetwo
' + 'threefour
onetwo
' + 'threefourLink
oneX
' + 'threefourLink
oneXtwo
' + 'threefourLink
onetwo
' + 'threefourLink
oneXtwo
' + 'threefourLink
onetwo
' + 'threefourLink
Xtwo
' + 'threefourLink
onetwo
' + 'threefourLink
oneXtwo
' + 'threefourLink
oneXtwo
' + 'threefourLink
This from
This from
This from
This from X by
one
para in div in list item
Next paragraph is in a list
First item
Second paragraph of first item
Second item
Third Item
fourth item
This paragraph is after the list
Next paragraph is in a list
First First item
Second paragraph of first item
Second item
Third Item
fourth item
This paragraph is after the list
Next paragraph is in a list
First item
Second paragraph of first item
Second item
Third Item
fourth item
This paragraph is after the list
Next paragraph is in a list
First item
Second paragraph of first item
Second item
Third Item
fourth item
This paragraph is after the list
Second item
Before a list
First item
Second item
Third Item
After the list
Before a list
First item
Second item
Third Item
After the list
Second item
AAA
BBB
CCC
DDD
AAA
BBB
CAAA
BBB
CC
DDD
AAA
BBB
CCC
DDD
AAA
BBB
CCC
DDD
AAA
BBB
AAA
BBB
CCC
DDD
AAA
BBB
CCC
DDD
AAA
BBB
one
two
three
one
tone
wo
three
ABC
DEF
GHI
ABC
DEF
GBC
DEHI
ABC
DEF
GHI
ABC
DEF
GBC
DEF
HI
ABC
DEF
ABC
DBC
EF
ABC
DEF
ABC
DEF
ABC
ABBC
ABC
DEF
ABC
DEFF
ABC
DEF
GHI
ABC
DEF
ABC
GHI
ABC
DEF
ABC
DABC
EF
pastedText
LinkNot
LinkpastedTextNot
LinkNot
LinkpastedTextNot
pastedText
A
B
A
pastedTextB
pastedText
pastedText
pastedText
pastedText
A
B
C
A
B
C
pastedText
A
A
pastedText