/**
* Copyright tepe ( http://wonderfl.net/user/tepe )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hRmd
*/
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.net.*;
import flash.ui.*;
public class FlashTest extends Sprite {
private var t1:TextEditor;//原文
private var t2:TextField;
private var t3:TextField;//正規表現
private var t4:TextField;
private var t5:TextField;//パラメータ
private var so : SharedObject;// = SharedObject.getLocal("my_data");
//区間開始
//(['"\{\(\[]|//|/\*)
//区間終了
//(['"\}\]\)]|\n|\*/)
public function FlashTest() {
// write as3 code here..
init();
}
private function init():void{
t1 = new TextEditor();
t2 = new TextField();
t3 = new TextField();
t4 = new TextField();
t5 = new TextField();
t1.border = true;
t1.width = 460;
t1.height = 200;
t1.wordWrap = true;
t1.y=40;
t1.type = "input";
//t1.multiline = true;
t1.text = "";
addChild(t1);
t1.addEventListener(KeyboardEvent.KEY_UP,onKey);
t1.addEventListener(Event.CHANGE,onChange);
//リスト
t2.y = 240;
t2.width=460;
t2.height=220;
t2.selectable=false;
addChild(t2);
t2.addEventListener(MouseEvent.MOUSE_MOVE,onMove1);
t2.addEventListener(MouseEvent.CLICK,onClick2);
//正規表現入力ボックス
t3.border = true;
t3.type = "input";
t3.width = 400;
t3.height =20;
t3.text = "<[\\S\\?]+[^>]*>";
addChild(t3);
t3.addEventListener(Event.CHANGE,onChange);
t3.addEventListener(KeyboardEvent.KEY_UP,addList);
t4.width = 450;
t4.height = 20;
t4.y = 20;
addChild(t4);
t5 = new TextField();//正規表現パラメータ
t5.border = true;
t5.type = "input";
t5.width = 50;
t5.height =20;
t5.x = 400;
addChild(t5);
t5.addEventListener(Event.CHANGE,onChange);
addEventListener(MouseEvent.CLICK,onClick);
t5.text = "gm";
so = SharedObject.getLocal("data");
if(so){
t1.text = "1";
var data:Object = so.data;
t1.text = "2";
//data["t1"] = "tst";
if(so.data.hasOwnProperty("t1"))t1.text = data["t1"];
if(so.data.hasOwnProperty("t2"))t2.text = data["t2"];
if(so.data.hasOwnProperty("t3"))t3.text = data["t3"];
//if(so.data.hasOwnProperty("t4"))t4.text = data["t4"];
if(so.data.hasOwnProperty("t5"))t5.text = data["t5"];
//t1.text = "3";
}
else{
t1.text = "0";
}
update();
}
private function onKey(e:KeyboardEvent):void{
update();
save();
}
private function onClick(e:MouseEvent):void{
update();
}
private function onChange(e:Event):void{
update();
}
private function save():void{
var data:Object = so.data;
data["t1"] = t1.text;
data["t2"] = t2.text;
data["t3"] = t3.text;
//data["t4"] = t4.text;
data["t5"] = t5.text;
so.flush();
}
private function onMove1(e:MouseEvent):void{
var mx:Number=e.target.mouseX;
var my:Number=e.target.mouseY;
var n:int = e.target.getLineIndexAtPoint(mx,my);//指定ポイントの行
font(t2,n);
}
private function onClick2(e:MouseEvent):void{
var mx:Number=e.target.mouseX;
var my:Number=e.target.mouseY;
var n:int = e.target.getLineIndexAtPoint(mx,my);//指定ポイントの行
t3.text = e.target.getLineText(n);
update();
}
//結果更新
private var ncnt:int = 0;
private function update():void{
//save();
if(t3.length<1)return;
var reg:RegExp = new RegExp(t3.text,t5.text);
reg.lastIndex = t1.caretIndex;
var result:Object = reg.exec(t1.text);
var str:String = t1.text;
//t4.text = "RegExp = /"+t3.text+"/"+t5.text + " start:"+t1.caretIndex +"index:"+result.index+" lastIndex:"+reg.lastIndex;
//検索ヒット
var newFormat:TextFormat = new TextFormat();
newFormat.size = 12;
newFormat.font = "Arial";
newFormat.color = 0xff0000;
newFormat.italic = true;
//検索ヒット
var newFormat2:TextFormat = new TextFormat();
newFormat2.size = 12;
newFormat2.font = "Arial";
newFormat2.color = 0xcc0000;
newFormat2.italic = true;
//通常フォーマット
var Format2:TextFormat = new TextFormat();
Format2.size = 12;
Format2.font = "Arial";
Format2.color = 0x000000;
Format2.italic = false;
t1.setTextFormat(Format2,0,t1.length);
//テキストフォーマットの設定(フォント設定, 適用開始位置, 適用終了位置)
//t1.setTextFormat(newFormat, result.index,reg.lastIndex);
t1.setTextFormat(newFormat, 0, t1.length);
var cnt:int=0;
ncnt++;
t4.text = ncnt.toString();
while (reg.lastIndex!=0) {
result = reg.exec(t1.text);
str = t1.text;
//フォーマット適用範囲を指定
//if((cnt%2)==1)t1.setTextFormat(newFormat, result.index,reg.lastIndex);
//else t1.setTextFormat(newFormat2, result.index,reg.lastIndex);
//t4.text = result.index.toString();
t4.text = reg.lastIndex.toString();
if((cnt%2)==1)newFormat.color = 0xcc0000;
else newFormat.color = 0xff0000;
t1.setTextFormat(newFormat, result.index,reg.lastIndex);
cnt++;
t4.text = cnt.toString();
//if(cnt>200)break;
}
t4.text = "---4 "+ ncnt.toString();;
t4.text = "RegExp = /"+t3.text+"/"+t5.text + " start:"+t1.caretIndex +"index:"+result.index+" lastIndex:"+reg.lastIndex;
}
//リストに追加
private function addList(e:KeyboardEvent=null):void{
if(e.keyCode==13){
if(t3.text.length==0)return;
var str:String = t3.text +"\n";
str += t2.text;
t2.text = str;
t3.text="";
}
}
//選択行を強調
private function font(t1:TextField,n:int):void{
//検索ヒット
var newFormat2:TextFormat = new TextFormat();
newFormat2.size = 15;
newFormat2.font = "Arial";
newFormat2.color = 0x000000;
newFormat2.italic = true;
//通常フォーマット
var Format2:TextFormat = new TextFormat();
Format2.size = 12;
Format2.font = "Arial";
Format2.color = 0x000000;
Format2.italic = false;
t1.setTextFormat(Format2,0,t1.length);//デフォルトフォーマット
var st:int = t1.getLineOffset(n);
var end:int = st+t1.getLineLength(n);
t1.setTextFormat(newFormat2,st,end);//デフォルトフォーマット
}
}
}
////////////////////////////////////////////////////////////////////////
// TextEditor class
////////////////////////////////////////////////////////////////////////
/*
--TextFieldへの追加機能--
・改行入力
・タブ入力
・オートインデント
・アンドゥ/リドゥ
*/
import flash.text.TextField;
import flash.events.*;
class TextEditor extends TextField {
private var prevText:String = "";//text変更前の状態
private var indentStr:String;
private var sc:StringComparator = new StringComparator();
private var historyManager:HistoryManager = new HistoryManager();
private var comparator:StringComparator = new StringComparator();
public function TextEditor():void {
this.type = "input";//入力可能
//this.multiline = true;//マルチライン
this.addEventListener(KeyboardEvent.KEY_DOWN, onKey);
this.addEventListener(FocusEvent.KEY_FOCUS_CHANGE,focusChangeListener);//タブキーによるフォーカス変更をキャンセル
this.addEventListener(Event.CHANGE,onChange);//textの変更
}
private var sw:Boolean;
private function onChange(e:Event):void{
if(sw==false)addHistory();
if(sw2==true){
this.multiline = false;
sw2=false;
}
prevText = this.text;
sw=false;
}
private function focusChangeListener(e:FocusEvent):void{
e.preventDefault();
}
//入力履歴更新
private function addHistory():void{
comparator.compare(prevText, this.text);
var entry:HistoryEntry = new HistoryEntry(comparator.commonPrefixLength);
entry.removeText = prevText.substring(comparator.commonPrefixLength, prevText.length - comparator.commonSuffixLength);
entry.addText = this.text.substring(comparator.commonPrefixLength, this.text.length - comparator.commonSuffixLength);
historyManager.appendEntry(entry);
prevText = this.text;
}
//キー入力
private var sw2:Boolean;
private function onKey(e:KeyboardEvent):void {
// Ctrl+Z : UNDO
if (e.keyCode == 90 && e.ctrlKey) {
sw=true;
undo();
return;
}
// Ctrl+Y : REDO
if (e.keyCode == 89 && e.ctrlKey) {
sw=true;
redo();
return;
}
//ペースト
if(e.keyCode == 86 && e.ctrlKey){
this.multiline = true;//改行を含むコピーに対応
sw2=true;
}
//キャレット位置に改行文字を挿入
if(e.keyCode == 13 || e.keyCode == 108){
lineFeed();
return;
}
//tab
if (e.keyCode == 9) {
tab();
return;
}
}
//改行
public function lineFeed():void{
//sw2=true;
var str1:String;
var str2:String;
var scrV:int = this.scrollV;
str1 = this.text.substring(0, this.caretIndex);
str2 = this.text.substring(this.caretIndex, this.length);
this.text = str1;
this.appendText("\n");//キャレット位置で改行
//インデント構造(タブ&スペースの構成)を調べる
var indent:int=0;
var prevReturn:int = this.text.lastIndexOf('\r', this.caretIndex-1);//前回の改行位置
//一つ前の改行直後に続くタブコードの数=インデント深度
for (var j:int = prevReturn+1; j < this.caretIndex; j++) {
if (this.text.charAt(j) == '\t' || this.text.charAt(j) == ' ' ) indent++;
else break;
}
//上の行のインデントに従う
var iStr:String = this.text.slice(prevReturn + 1, prevReturn + 1 + indent);
indentStr = iStr;
this.appendText(iStr);//インデント
this.text += str2;//結合
//キャレット位置をインクリメント
this.scrollV = scrV;
this.setSelection(this.caretIndex +indent + 1, this.caretIndex +indent + 1);
this.dispatchEvent(new Event(Event.CHANGE));
}
//タブ
public function tab():void{
var str1:String;
var str2:String;
str1 = this.text.substring(0, this.caretIndex);
str2 = this.text.substring(this.caretIndex, this.length);
this.text = str1 + '\t' + str2;
//キャレット位置をインクリメント
this.setSelection(this.caretIndex + 1, this.caretIndex + 1);
this.dispatchEvent(new Event(Event.CHANGE));
}
//アンドゥ
public function undo():void {
if (historyManager.canBack) {
var entry:HistoryEntry = historyManager.back();
//テキストセット
this.replaceText(entry.index, entry.index + entry.addText.length, entry.removeText);
//キャレット位置セット
this.setSelection(entry.index + entry.removeText.length, entry.index + entry.removeText.length);
}
this.dispatchEvent(new Event(Event.CHANGE));
}
//リドゥ
public function redo():void {
if (historyManager.canForward) {
var entry:HistoryEntry = historyManager.forward();
//テキストセット
this.replaceText(entry.index, entry.index + entry.removeText.length, entry.addText);
//キャレット位置セット
this.setSelection(entry.index + entry.addText.length, entry.index + entry.addText.length);
}
this.dispatchEvent(new Event(Event.CHANGE));
}
}
import __AS3__.vec.Vector;
class HistoryManager {
public var currentIndex:int = 0;
public var length:int=0;
private var entries:Vector.<HistoryEntry>;
public function HistoryManager() {
entries = new Vector.<HistoryEntry>();
}
//履歴追記
public function appendEntry(entry:HistoryEntry):void {
entries.length = currentIndex;
length = entries.length;
entries.push(entry);
currentIndex++;// = entries.length;
}
//履歴削除
public function clear():void {
currentIndex = 0;
entries.length = 0;
}
//リドゥ可能
public function get canForward():Boolean {
return currentIndex < entries.length;
}
//アンドゥ可能
public function get canBack():Boolean {
return currentIndex > 0;
}
//リドゥ
public function forward():HistoryEntry {
return entries[currentIndex++];
}
//アンドゥ
public function back():HistoryEntry {
return entries[--currentIndex];
}
}
class HistoryEntry {
public var index:int;
public var removeText:String;
public var addText:String;
public function HistoryEntry(index:int=0, remove:String="", add:String="") {
this.index = index;//文字列先頭位置
this.removeText = remove;//消した文字列
this.addText = add;//追加した文字列
}
}
// 文字列の左右一致を数える
class StringComparator {
// 左側の共通文字列長
public var commonPrefixLength:int;
// 右側の共通文字列長
public var commonSuffixLength:int;
/**
* 2つの文字列を比較し、commonPrefixLengthとcommonSuffixLengthをセットする
*
* @param str1 比較する文字列の一方
* @param str2 比較する文字列の他方
*/
public function compare(str1:String, str2:String):void {
var minLength:int = Math.min(str1.length, str2.length);
var step:int, l:int, r:int;
step = Math.pow(2, Math.floor(Math.log(minLength) / Math.log(2)));
for (l=0; l<minLength; ) {
if (str1.substr(0, l + step) != str2.substr(0, l + step)) {
if (step == 1) { break; }
step >>= 1;
} else {
l += step;
}
}
l = Math.min(l, minLength);
minLength -= l;
step = Math.pow(2, Math.floor(Math.log(minLength) / Math.log(2)));
for (r=0; r<minLength; ) {
if (str1.substr(-r - step) != str2.substr(-r - step)) {
if (step == 1) { break; }
step >>= 1;
} else {
r += step;
}
}
r = Math.min(r, minLength);
commonPrefixLength = l;
commonSuffixLength = r;
}
}