//Undo/RedoをサポートしたTextField //Ctrl+ZでUndo、Ctrl+YでRedoです。 package { import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFieldType; public class a extends Sprite { public function a() { var text:TextField = new UndoRedoTextField(); text.border = true; text.selectable = true; text.type = TextFieldType.INPUT; text.multiline = true; text.width = 300; text.height = 300; addChild(text); } } } import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.TextEvent; import flash.text.TextField; class UndoRedoTextField extends TextField { private var _lastLength:int; private var _lastText:String; private var _redoIndex:int; private var _undoBuffer:Array; public function UndoRedoTextField() { _undoBuffer = []; addEventListener(TextEvent.TEXT_INPUT, textInputHandler); addEventListener(Event.CHANGE, changeHandler); addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); } public function redo():void { if (redoEnabled) { applyInfo(_undoBuffer[_undoBuffer.length - _redoIndex--], false); } } public function get redoEnabled():Boolean { return _redoIndex > 0; } public function undo():void { if (undoEnabled) { applyInfo(_undoBuffer[_undoBuffer.length - ++_redoIndex], true); } } public function get undoEnabled():Boolean { return _undoBuffer.length > _redoIndex; } private function applyInfo(info:UndoInfo, undo:Boolean):void { if (info === null) { return; } var prefix:String, suffix:String, result:String, ci:int = info.caretIndex; if ((info.input && undo) || (!info.input && !undo)) { prefix = _lastText.substring(0, ci); suffix = _lastText.substring(ci + info.length); result = prefix + suffix; } else { prefix = _lastText.substring(0, ci); suffix = _lastText.substring(ci); result = prefix + info.text + suffix; } text = result; if (undo) { setSelection(ci, ci); } else { setSelection(ci + info.length, ci + info.length); } _lastLength = result.length; _lastText = result; } private function changeHandler(e:Event):void { var len:int = length; var ci:int = caretIndex; if (_lastLength > len) { pushUndoBuffer(new UndoInfo(false, ci, _lastText.substring(ci, ci + _lastLength - len), _lastLength - len)); } _lastLength = len; _lastText = text; } private function keyDownHandler(e:KeyboardEvent):void { if (e.ctrlKey && !e.altKey && !e.shiftKey) { switch (e.keyCode) { case 90: undo(); return; case 89: redo(); return; default: return; } } } private function pushUndoBuffer(info:UndoInfo):void { if (_redoIndex > 0) { _undoBuffer.splice(_undoBuffer.length - _redoIndex); } _redoIndex = 0; _undoBuffer.push(info); } private function textInputHandler(e:TextEvent):void { pushUndoBuffer(new UndoInfo(true, caretIndex, e.text, e.text.length)); } } class UndoInfo { public var caretIndex:int; public var input:Boolean; public var length:int; public var text:String; public function UndoInfo(input:Boolean, caretPosition:int, text:String, length:int) { this.input = input; this.caretIndex = caretPosition; this.length = length; this.text = text; } } Undo/Redoに対応したTextField