//テキストエリア用クラス
var compTextarea = Class.create();
var textareaComp = Array();
/*
    モジュール側のjavascriptクラスから
    this.textarea = new parent.compTextarea();
    this.textarea.textareaShow(this.id, "announcement_text", "full");
    のように使用
*/
compTextarea.prototype = {
	initialize: function() {
		this.textarea = null;
		this.htmlarea = null;
		this.toolbar = null;
		this.mode = null;	//simple or medium or full
		
		//同じIDでtextareaを２つ表示する場合、prefixをつけること
		this.popupPrefix = "";
		
		//this.prevRange = null;
		this.text = null;
		this.text_style = null;
		this.text_content = null;
		//this.statusbar = null;
		this.resizeBox = null;

		this.config =  new Object();
		this.timerToolbar = null;
		this.toolbarObjects = null;

		//カスタムUNDO REDO
		this.custom_undo_redo = true;
		this.custom_undo_redo_maxlevels = 100;
		this.custom_undo_redo_levels = -1;
		this.custom_undo_redo_keyboard_shortcuts = true;	//Ctrl+ZでUNDO Ctrl＋RでREDO

		this.setStartsBarDragGoEvent = null;
		this.setStartsBarDragStopEvent = null;
		this.htmlareaMinWidth = 0;
		this.htmlareaMinHeight = 0;
		this.htmlareaOldWidth = 0;
		this.htmlareaOldHeight = 0;
		this.resizeBoxSize = 0;
		//Edit Html Preview
		this.editMode = "edit";
		this.oldeditMode = "edit";

		this.editModeBtn = null;
		this.htmlModeBtn = null;
		this.previewModeBtn = null;
		
		this.change_el = null;	//color変更elment保存用
		
		this.preSel = null;
		this.preRange = null;	//メイン選択範囲
		this.el = null;			//内部エレメント保存用
		this.el_array = [];		
		//this.currentEvent = null;	//カレントevent
		
		this.inAddEvent = false;
		
		this.update_flag = false;	//updateダイアログか否か
		//tableプロパティ
		this.tableProperty  = { 	
					f_rows: 			0, 
					f_cols: 			0,
					f_width: 			"200",
					f_w_unit: 			"px",
					f_height: 			"",
					f_h_unit: 			"px",
					f_align: 			"",
					f_background: 		"",
					f_border: 			"1",
					f_border_style:		"solid",
					f_border_color:		"#000000",
					f_spacing: 			"0",
					f_padding: 			"0",
					f_horiz: 			"5",
					f_vert: 			"5",
					f_fixed:			false,
					f_collapse:			true,
					r_align: 			"",
					r_valign: 			"",
					r_width: 			"",
					r_w_unit: 			"px",
					r_height: 			"",
					r_h_unit: 			"px",
					r_background: 		"",
					r_fontcolor: 		"",
					c_align: 			"",
					c_valign: 			"",
					c_width: 			"",
					c_w_unit: 			"px",
					c_height: 			"",
					c_h_unit: 			"px",
					c_background: 		"",
					c_fontcolor: 		"",
					c_nowrap:			false,
					c_t_border: 		"1",
					c_t_border_style:	"solid",
					c_t_border_color:	"#000000",
					c_r_border: 		"1",
					c_r_border_style:	"solid",
					c_r_border_color:	"#000000",
					c_b_border: 		"1",
					c_b_border_style:	"solid",
					c_b_border_color:	"#000000",
					c_l_border: 		"1",
					c_l_border_style:	"solid",
					c_l_border_color:	"#000000"
				};

		this.linkProperty  = {
					f_href : '',
					f_title : '',
					f_target : '',
					f_usetarget : true
				};
		this.imageProperty  = {
					f_base   : '',
					f_url    : '',
					f_alt    : '',
					f_border : '',
					f_align  : '',
					f_vert   : '',
					f_horiz  : ''
				};
		this.texProperty  = {
					f_texexp : ''
				};
		
		this.id = null;
		this.popup = new Object();
		/* アップロードするためのアクション名指定 */
		/* 指定しない場合、アップロードを許さない */
		this.uploadAction  = {
					image   : null,
					file    : null,
					token   : null
				};
		this.topAddEventFunc = null;
		//Safariに対応するために追加　Dialog表示前の状態保存用
		this.preSel = null;
		this.startNode = null;
		this.startOffset = null;
		this.endNode = null;
		this.endOffset = null;
		this.sizeElement = null;
		
		this.timer = null;
	},
	//テキストエリア表示関数
	textareaShow: function(id, textarea_classname, mode, config) {
		this.popupPrefix = textarea_classname;
		var text_el = Element.getChildElementByClassName($(id),textarea_classname);
		this.textareaEditShow(id,text_el, mode);
	},
	textareaEditShow: function(id,textarea,mode,config) {
		mode = (mode == undefined) ? "full" : mode;
		commonCls.referComp[id+this.popupPrefix] = this;

		this.id = id;
		var textarea = $(textarea);
		if (browser.isIE) {
			for (var i = 1; i < document.styleSheets.length; i++) {
				var paths = document.styleSheets[i].href.split("/");
				if (paths[paths.length - 1] == "comp_textarea.css") {
					var rule = document.styleSheets[i].rules[0];
					break;
				}
			}
			textarea.style.width = rule.style.width;
			textarea.style.height = rule.style.height;
		}

		this.textarea = textarea;
		
		var ta_size = {
			w: valueParseInt(textarea.offsetWidth),		//textarea.style.width,
			h: valueParseInt(textarea.offsetHeight) 	//textarea.style.height
		};
		if (textarea.style.width) {
			ta_size.w = valueParseInt(textarea.style.width);
		}
		if (textarea.style.height) {
			ta_size.h = valueParseInt(textarea.style.height);
		}
		/*
		//if(this.textarea.style.display == "none" || Element.hasClassName(this.textarea,"display-none")) {
		
		if(this.textarea.style.display == "none") {
			//既に初期化済
			this.oldeditMode = this.editMode;
			this.editMode = "edit";
			this.changeEditMode();
			//commonCls.displayChange(this.textarea);
			this.text_content.body.innerHTML = this.textarea.value;

			//if(this.editMode != "preview")
				(this.text_content.body.contentEditable != undefined) ? this.text_content.body.contentEditable = true : this.text_content.designMode = "on";
			//commonCls.displayChange(this.textarea);
			return;
		}
		*/
		
		//textarea非表示
		commonCls.displayNone(this.textarea);
		//commonCls.displayChange(this.textarea);
		
		this.htmlarea = document.createElement("DIV");
		Element.addClassName(this.htmlarea,"comptextarea_textarea");
		//this.htmlarea.className ="comptextarea_textarea";
		
		// insert the editor before the textarea.
		textarea.parentNode.insertBefore(this.htmlarea, textarea);
		//textarea.appendChild(this.htmlarea);
	
		//ラベル読み込み
		if (typeof config == "undefined") {
			this.getConfig(mode);
		} else {
			this.config = config;
		}
		this.undoLevels = new Array(this.custom_undo_redo_maxlevels);
	
		//------------------------------
		//ボタン追加
		//------------------------------
		this.toolbar = document.createElement("DIV");
		//this.toolbar.style.width = "0px";
		this.htmlarea.appendChild(this.toolbar);
		this.createToolbar();
		//------------------------------
		//Edit TextArea作成
		//------------------------------
		var text = document.createElement("IFRAME");	
		text.src='about:blank';
		//Event.observe(text,"load",this.winIframeLoad,false);
		////text.id = textarea+"_text";
		Element.addClassName(text,"comptextarea_text");
		var height = (this.config.height == undefined || this.config.height == "auto" ? (ta_size.h + "px") : this.config.height);
		height = parseInt(height);
		var width = (this.config.width == undefined || this.config.width == "auto" ? (ta_size.w + "px") : this.config.width);
		width = valueParseInt(width);
		//if (!(browser.isIE || browser.isOpera)) {
		////	height -= 2;
		////	width -= 2;
		//}
		//ne.onkeydown = new Function("checkPaste();");
		//ne.ondragend = new Function("borderToggle(false)");
		//ne.oncontextmenu = new Function("contextToggle()");
		this.text_style = text.style;
		this.setTextAreaStyle(text);
		this.setTextAreaStyle(textarea);
		
		this.text_style.width = width + 'px';
		this.text_style.height = height + 'px';
		this.htmlareaOldWidth = width;
		this.htmlareaOldHeight = height;
		
		//if(!(browser.isIE || browser.isOpera)) {
		//	if(this.toolbar.offsetWidth > width)
		//		width = this.toolbar.offsetWidth - valueParseInt(Element.getStyle(text,"borderRightWidth"))  - valueParseInt(Element.getStyle(text,"borderLeftWidth")) - valueParseInt(Element.getStyle(text,"marginRight"))  - valueParseInt(Element.getStyle(text,"marginLeft"));
		//}
		
		this.htmlarea.style.width = width + valueParseInt(Element.getStyle(text,"borderRightWidth"))  + valueParseInt(Element.getStyle(text,"borderLeftWidth")) + valueParseInt(Element.getStyle(text,"marginRight"))  + valueParseInt(Element.getStyle(text,"marginLeft")) + 'px';
		//this.text_style.overflow = 'auto';
		this.text_style.wordWrap = 'break-word';
		//this.htmlarea.appendChild(text);
		//text.parentNode.insertBefore(this.textarea,text);
	
		this.topAddEventFunc = this.topAddEvent.bindAsEventListener(this);
		Event.observe(text,"load",this.topAddEventFunc, false, this.id);
			
		this.text = text;
		if(browser.isSafari) {
			//text.setAttribute("src", "./images/comp/textarea/blank.html");
			this.timer = setInterval(this.topAddEventFunc, 500);
			//setTimeout(this.topAddEventFunc, 100);
		}
		
		this.htmlarea.appendChild(text);
		text.parentNode.insertBefore(this.textarea,text);	
	
		//StatusBar
		var statusbar = document.createElement("DIV");
		statusbar.className = "comptextarea_statusBar";
		//Element.addClassName(statusbar,"comptextarea_statusBar");
		////statusbar.id = textarea+"_statusbar";
		////statusbar.className = "statusBar";
		//var statusbarHTML = '<div class="statusBarButton">&nbsp;</div><div class="statusBarResize" onmousedown="this.setStartsBarResizing(event).bindAsEventListener(this);"></div><br style="clear: both" />';
		//statusbar.innerHTML = statusbarHTML;
		
		var statusbar_btn = document.createElement("DIV");
		statusbar_btn.className = "comptextarea_statusBarButton";
		var doc = document.createDocumentFragment();
		table = document.createElement("table");
		table.border = "0";
		table.cellSpacing = "0";
		table.cellPadding = "0";
		var tb_body = document.createElement("tbody");
		table.appendChild(tb_body);
		var tb_row = document.createElement("tr");
		tb_body.appendChild(tb_row);
		var td1 = document.createElement("td");
		td1.className = "comptextarea_changeMode comptextarea_editMode comptextarea_activeMode";
		tb_row.appendChild(td1);
		
		var td2 = document.createElement("td");
		td2.className = "comptextarea_changeMode comptextarea_htmlMode";
		tb_row.appendChild(td2);
		
		var td3 = document.createElement("td");
		td3.className = "comptextarea_changeMode comptextarea_previewMode";
		tb_row.appendChild(td3);
		
		var a1 = document.createElement("a");
		var a2 = document.createElement("a");
		var a3 = document.createElement("a");
		a1.style.width = "100%";
		a1.style.display = "block";
		a2.style.width = "100%";
		a2.style.display = "block";
		a3.style.width = "100%";
		a3.style.display = "block";
		//a1.className = "widthmax display-block link";
		//a2.className = "widthmax display-block link";
		//a3.className = "widthmax display-block link";
		td1.appendChild(a1);
		td2.appendChild(a2);
		td3.appendChild(a3);
		if (typeof compTextareaLang == "undefined" || typeof compTextareaLang.modetype["edit"] == "undefined") 
			var txt1 = document.createTextNode('Edit');
		else
			var txt1 = document.createTextNode(compTextareaLang.modetype["edit"]);
		if (typeof compTextareaLang == "undefined" || typeof compTextareaLang.modetype["html"] == "undefined") 
			var txt2 = document.createTextNode('Html');
		else
			var txt2 = document.createTextNode(compTextareaLang.modetype["html"]);
		if (typeof compTextareaLang == "undefined" || typeof compTextareaLang.modetype["preview"] == "undefined") 
			var txt3 = document.createTextNode('Preview');
		else
			var txt3 = document.createTextNode(compTextareaLang.modetype["preview"]);
		a1.appendChild(txt1);
		a2.appendChild(txt2);
		a3.appendChild(txt3);
		
		this.editModeBtn = td1;
		this.htmlModeBtn = td2;
		this.previewModeBtn = td3;
		Event.observe(a1, "click", function (event) {
					this.oldeditMode = this.editMode;
					this.editMode = "edit";
					this.changeEditMode();
					Event.stop(event);
					return false;
				}.bindAsEventListener(this),false, this.id);
		Event.observe(a2, "click", function (event) {
					this.oldeditMode = this.editMode;
					this.editMode = "html";
					this.changeEditMode();
					Event.stop(event);
					return false;
				}.bindAsEventListener(this),false, this.id);
		Event.observe(a3, "click", function (event) {
					this.oldeditMode = this.editMode;
					this.editMode = "preview";
					this.changeEditMode();
					Event.stop(event);
					return false;
				}.bindAsEventListener(this),false, this.id);
		
		statusbar_btn.appendChild(table);
		//doc.appendChild(table);
		//statusbar_btn.appendChild(doc);
		
		statusbar.appendChild(statusbar_btn);
		var statusbar_resize = document.createElement("DIV");
		statusbar_resize.className = "comptextarea_statusBarResize";
		//Element.addClassName(statusbar_resize,"comptextarea_statusBarResize");
		//statusbar_resize.className = "statusBarResize";
		Event.observe(statusbar_resize,"mousedown",this.setStartsBarResizing.bindAsEventListener(this),false, this.id);

		statusbar.appendChild(statusbar_resize);
		var br = document.createElement("BR");
		br.style.clear = "both";
		statusbar.appendChild(br);
		
		doc.appendChild(statusbar);
		this.htmlarea.appendChild(doc);
		
		//this.htmlarea.appendChild(statusbar);
		
		//this.statusbar = statusbar;
		//ResizeBox
		//var resizeBox = document.createElement("DIV");
		//this.resizeBox = resizeBox;
		//this.resizeBox.style.display = "none";
		//this.resizeBox.style.border= "1px dotted #666666";
		//Element.getParentElement(this.htmlarea).appendChild(this.resizeBox);

		//this.htmlareaMinHeight = this.htmlarea.clientHeight;
		this.htmlareaMinHeight = this.text.clientHeight;
		this.htmlareaMinWidth = this.text.clientWidth;
		
		//colorデフォルト値指定
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_setforecolor");
		if(el) el.style.backgroundColor = "#ff0000";
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_sethilitecolor");
		if(el) el.style.backgroundColor = "#ff0000";
	},
	topAddEvent: function(event) {
		var text = this.text;
		if(!browser.isGecko && !browser.isSafari){
			Event.stopObserving(text,"load", this.topAddEventFunc, false);
		} else if(browser.isSafari) {
			//Safariの場合、iframe-Loadイベントが動かないため
			try{
				var tmp = text.contentWindow.document;
				if(tmp == undefined || tmp == null) {
					return;
				}
			} catch(e) { 
				return;
			}
			clearInterval(this.timer);
		}
		if(!text.contentWindow || !text.contentWindow.document) {
			////setTimeout(this.topAddEventFunc, 100);
			return;
		}
		this.text_content = text.contentWindow.document;			
		if(this.inAddEvent == false && text.contentWindow.document.body.innerHTML.strip() == "") {
			this.inAddEvent = true;
			var text_content = this.text_content;
			if(browser.isNS){
				text_content.designMode = "on";
			}
			var htmltag = document.getElementsByTagName("html")[0];
			var htmlAttr = "xmlns=\"" + htmltag.getAttribute("xmlns") + "\" ";
			var head = document.getElementsByTagName("head")[0];
			var links = head.getElementsByTagName("link");
			if (typeof compTextareaLang != "undefined" && typeof compTextareaLang.content["title"] != "undefined") 
				var titleText = "<title>" + compTextareaLang.content["title"] + "</title>\n"
			text_content.open();
			var html = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
			html += "<html " + htmlAttr + ">\n";
			var styleText =  "<style> html,body { height : 100% !important; background-image : none !important; padding:0px; margin:0px !important;}\n " + 
							".comptextareat_content {background-color:#ffffff; border: 0px;font-size:80%;color: #666666;}\n" +
							" table {font-size:small;}" +
							"</style>\n" +
							"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=euc-jp\">";	//追加
			html += "<head>" + titleText + styleText + "</head>\n";	
			if(this.textarea.value == "") {
				this.textarea.value = "<br />";
			}
			html += "<body class=\"comptextareat_content\">\n" + this.textarea.value + "</body>\n" + "</html>";
			////html += "<head>" + titleText + linkText + "</head>\n";
//			var html = "<html>\n";
//html += "<head>" + titleText + linkText + "</head>\n";
			//html += "<head>\n";
			//if (editor.config.baseURL)
			//	html += '<base href="' + editor.config.baseURL + '" />';
			//html += "<style> html,body { border: 0px; } " +
			//	editor.config.pageStyle + "</style>\n";
			//html += "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"./css/common/style.css\" />\n";
			//var theme_name = $_GET("theme_name");
			//if(theme_name) {
			//	html += "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"./css/space/"+ theme_name + "/style.css\" />\n";
			//}
			//html += "<style> html,body { border: 0px; background-color:#ffffff;font-size:90%;} td {font-size:90%;} " + "</style>\n";
			//html += "</head>\n";
			text_content.write(html);
			text_content.close();
			this.chgStyleSheet();
			
			//&nbsp変換処理
			//text_content.body.innerHTML = this.getHTMLWrapper(this.text_content.body, false, this);
			
			Event.observe(text_content,"keyup",this.handleEvent.bindAsEventListener(this),false, this.id);
			Event.observe(text_content,"mouseup",this.handleEvent.bindAsEventListener(this),false, this.id);
			Event.observe(text_content,"keydown",this.handleEvent.bindAsEventListener(this),false, this.id);
			//ダブルクリック時イベント
			Event.observe(text_content, "dblclick", function (event) {
				if(this.editMode == "edit") {
					var el = Event.element(event);
					if(el.tagName.toLowerCase() == 'table') {
						//IEのみ対応
						this.showTableSetProperty(el);
					}else if(el.tagName.toLowerCase() == 'img') {
						if(el.src.indexOf(_js_url +"/include/comp/textarea/tex.php?c=", 0) == -1) {
							this.insertImageDialog(el);
						}else{
							this.insertTexDialog(el);
						}
					}
				}
			}.bindAsEventListener(this),false, this.id);
			if(!browser.isNS){
				(text_content.body.contentEditable != undefined) ? text_content.body.contentEditable = true : text_content.designMode = "on";
			}
			if(this.textarea.value == "") {
				var value = (browser.isIE || browser.isOpera) ? "<div>" : "br";
				this.execCommand("formatblock", false, value);
			}
			this.forceRedraw();
			//if(browser.isIE) {
			//	setTimeout(function() {this.focusEditor(true);}.bind(this), 1000);
			//} else {
			//	this.focusEditor(true);
			//}
			this.inAddEvent = false;
		}
		this.borderChange();
	},
	chgStyleSheet: function(add_flag) {
		add_flag = (add_flag == undefined) ? true : add_flag;
		if(add_flag) {
			var head = document.getElementsByTagName("head")[0];
		} else {
			var head = this.text_content.getElementsByTagName("head")[0];
		}
		var links = head.getElementsByTagName("link");
		if(add_flag == true) {
			if(typeof this.text_content.createStyleSheet != "undefined") {
				var createStyleSheetFlag = true;
			} else {
				var createStyleSheetFlag = false;
				var insert_head = this.text_content.getElementsByTagName("head")[0];
			}
		} else {
			var remove_obj = new Object;
		}
		for (var i = 0,links_length = links.length; i < links_length; i++) {
			var link = links[i];
			if (link.getAttribute("type") == "text/css") {
				if(add_flag) {
					if(createStyleSheetFlag) {
						this.text_content.createStyleSheet(link.getAttribute("href"));
					} else {
						var append_link = document.createElement('LINK');
						append_link.rel = link.getAttribute("rel");
						append_link.type = link.getAttribute("type");
						append_link.media = link.getAttribute("media");
						append_link.href= link.getAttribute("href");
						insert_head.appendChild(append_link);
					}
				} else {
					remove_obj[i] = link;
				}
			}
		}
		if(!add_flag) {
			for (var link in remove_obj) {
				Element.remove(remove_obj[link]);
			}
			//Element.addClassName(this.text_content.body, "comptextareat_content");
			this.text_content.body.style.backgroundColor = "";
			this.text_content.allowtransparency = false;
		} else {
			//Element.removeClassName(this.text_content.body, "comptextareat_content");
			////this.text_content.body.style.backgroundColor = "transparent";
			var el = this.textarea; //this.htmlarea.parentNode;
			var color = commonCls.getColorCode(el, "backgroundColor");
			if (color == "transparent") {
				var parent_el = el;
				while (color == "transparent") {
					if(this.textarea == parent_el) parent_el = this.htmlarea.parentNode;
		        	else parent_el = parent_el.parentNode;
		        	if(parent_el.tagName == "BODY") {
		        		color = "#ffffff";
		        		break;
		        	}
		        	color = commonCls.getColorCode(parent_el, "backgroundColor");
		    	}
			}
			this.text_content.body.style.backgroundColor = color;
			this.text_content.allowtransparency = true;
		}
	},
	textareaEditHide: function() {
		(this.text_content.body.contentEditable != undefined) ? this.text_content.body.contentEditable = false : this.text_content.designMode = "off";
		//undo　リセット
		delete(this.undoLevels);
		this.undoLevels = new Array(this.custom_undo_redo_maxlevels);
		this.custom_undo_redo_levels = -1;
	},
	forceRedraw: function() {
		this.text_content.body.style.display = "none";
		this.text_content.body.style.display = "";
	},
	//style: "" ,"none"
	toolbarVisble: function(style) {
		if(style == undefined)
			style = "";
		this.toolbar.style.display = style;
	},
	setTextAreaStyle: function(el) {
		var el_style = el.style;
		////el_style.backgroundColor = '#ffffff';
		el_style.borderTop  = '1px solid #666666';
		el_style.borderBottom = '1px solid #cccccc';
		el_style.borderLeft = '1px solid #666666';
		el_style.borderRight = '1px solid #cccccc';
		el.marginHeight = "0";
		el.marginWidth = "0";
		el_style.marginTop="0px"
		el_style.marginRight="5px"
		el_style.marginLeft="5px"
	},
	getConfig: function(mode) {
		//ブラウザにより、使用できないボタンを非表示へ
		//使用できるように修正する場合、こちらをコメントにすること  
		if(browser.isSafari && mode != "least") {
			mode = "safari";
		} else if(browser.isOpera && mode == "full") {
			//Operaで現状使用できないもの：outdent,indent,inserttable,tablemenu
			mode = "medium";
		}
		//----------
		if(mode == "full") {
			
			this.config.toolbar = [
				[	"fontname", "space",
			  		"fontsize", "space",
			  		"formatblock", "space",
					"bold", "italic", "underline", "strikethrough", "separator",
					"subscript", "superscript", "separator", 
					"setforecolor","forecolor", "sethilitecolor","hilitecolor", "separator", 
					"removeformat"
				],
				[ "undo", "redo", "separator", 
	//				"copy", "cut", "paste", "separator",
	//				"lefttoright", "righttoleft", "separator",
					"justifyleft", "justifycenter", "justifyright", "separator",
					"orderedlist", "unorderedlist", "separator",
					"outdent", "indent", "separator",
					"inserttable","tablemenu", "separator","inserthorizontalrule","separator",
					"insertsmiley","separator","inserttex","separator",
					"createlink", "unablelink", "separator","savezip","space","insertimage"
				]
			];
		} else if(mode == "medium") {
			this.config.toolbar = [
				[	"fontname", "space",
			  		"fontsize", "space",
			  		"formatblock", "space",
					"bold", "italic", "underline", "strikethrough", "separator",
					"subscript", "superscript", "separator", 
					"setforecolor","forecolor", "sethilitecolor","hilitecolor", "separator", 
					"removeformat"
				],
				[ "undo", "redo", "separator", 
	//				"copy", "cut", "paste", "separator",
	//				"lefttoright", "righttoleft", "separator",
					"justifyleft", "justifycenter", "justifyright", "separator",
					"orderedlist", "unorderedlist", "separator",
	//				"outdent", "indent", "separator",
	//				"inserttable","tablemenu", "separator","inserthorizontalrule","separator",
					"insertsmiley","separator","inserttex","separator",
					"createlink", "unablelink", "separator","savezip","space","insertimage"
				]
			];
		} else if(mode == "least") {
			this.config.toolbar = [
				[	"undo", "redo", "separator", 
				 	"bold", "italic", "underline", "strikethrough", "separator",
					"setforecolor","forecolor", "sethilitecolor","hilitecolor", "separator", 
					"removeformat", "separator",
					"createlink", "unablelink"
				]
			];
		} else if(mode == "safari") {
			this.config.toolbar = [
				[	"fontsize", "space",
					"undo", "redo", "separator", 
				 	"bold", "italic", "underline", "strikethrough", "separator",
					"subscript", "superscript", "separator", 
					"setforecolor","forecolor", "sethilitecolor","hilitecolor", "separator", 
					"insertsmiley","separator","inserttex","separator",
					"createlink", "unablelink", "separator","insertimage"
				]
			];
		} else {
			this.config.toolbar = [
				[	"undo", "redo", "separator", 
				 	"bold", "italic", "underline", "strikethrough", "separator",
					"subscript", "superscript", "separator", 
					"setforecolor","forecolor", "sethilitecolor","hilitecolor", "separator", 
					"removeformat", "separator", "insertsmiley","separator",
					"createlink", "unablelink", "separator","insertimage"
				]
			];
		}
		if (mode != "least" && _allow_attachment != 0 && this.uploadAction.file != null) {
			if(this.config.toolbar[1]) {
				this.config.toolbar[1].push("insertupload");
			} else {
				this.config.toolbar[0].push("insertupload");
			}
		}
		if (typeof compTextareaLang != "undefined" && typeof compTextareaLang.fontname != "undefined") {
			this.config.fontname = compTextareaLang.fontname;
		} else {
			this.config.fontname = {
				"&mdash; font &mdash;":         '',
				"Arial":	   'arial,helvetica,sans-serif',
				"Courier New":	   'courier new,courier,monospace',
				"Georgia":	   'georgia,times new roman,times,serif',
				"Tahoma":	   'tahoma,arial,helvetica,sans-serif',
				"Times New Roman": 'times new roman,times,serif',
				"Verdana":	   'verdana,arial,helvetica,sans-serif',
				"impact":	   'impact',
				"WingDings":	   'wingdings'
			};
		}

		if (typeof compTextareaLang != "undefined" && typeof compTextareaLang.fontsize != "undefined") {
			this.config.fontsize = compTextareaLang.fontsize;
		} else {
			this.config.fontsize = {
				"size"  : "",
				"1 (8 pt)" : "1",
				"2 (10 pt)": "2",
				"3 (12 pt)": "3",
				"4 (14 pt)": "4",
				"5 (18 pt)": "5",
				"6 (24 pt)": "6",
				"7 (36 pt)": "7"
			};
		}

		this.config.customSelects = {};

		if (typeof compTextareaLang != "undefined" && typeof compTextareaLang.format != "undefined") {
			this.config.formatblock = compTextareaLang.format;
		} else {
			this.config.formatblock = {
				"format"  : "",
				"Heading 1": "h1",
				"Heading 2": "h2",
				"Heading 3": "h3",
				"Heading 4": "h4",
				"Heading 5": "h5",
				"Heading 6": "h6",
				"Normal"   : "div",
				"Address"  : "address",
				"Formatted": "pre"
			};
		}
		
		//ボタンリスト：Dafault Lang,画像名称,実行関数名
		this.config.btnList = {
			undo: ["Undo", "toolbar/ed_undo.gif",false, function(cmdID,UI,param) {this.execCommand("undo");}.bind(this), "comptextarea_button_l"],
			redo: ["Redo", "toolbar/ed_redo.gif",false, function(cmdID,UI,param) {this.execCommand("redo");}.bind(this), "comptextarea_button_r"],
			copy: ["Copy", "toolbar/ed_copy.gif", false, function(cmdID,UI,param) {this.execCommand("copy");}.bind(this), "comptextarea_button_l"],
			cut:  ["Cut", "toolbar/ed_cut.gif", false,  function(cmdID,UI,param) {this.execCommand("cut");}.bind(this), "comptextarea_button_c"],
			paste:["Paste", "toolbar/ed_paste.gif", false, function(cmdID,UI,param) {this.execCommand("paste");}.bind(this), "comptextarea_button_r"],
			bold: [ "Bold", "toolbar/ed_format_bold.gif", false, function(cmdID,UI,param) {this.execCommand("bold");}.bind(this), "comptextarea_button_l"],
			italic: [ "Italic", "toolbar/ed_format_italic.gif", false, function(cmdID,UI,param) {this.execCommand("italic");}.bind(this), "comptextarea_button_c"],
			underline: [ "Underline", "toolbar/ed_format_underline.gif", false, function(cmdID,UI,param) {this.execCommand("underline");}.bind(this), "comptextarea_button_c"],
			strikethrough: [ "Strikethrough", "toolbar/ed_format_strike.gif", false, function(cmdID,UI,param) {this.execCommand("strikethrough");}.bind(this), "comptextarea_button_r"],
			subscript: [ "Subscript", "toolbar/ed_format_sub.gif", false, function(cmdID,UI,param) {this.execCommand("subscript");}.bind(this) , "comptextarea_button_l"],
			superscript: [ "Superscript", "toolbar/ed_format_sup.gif", false, function(cmdID,UI,param) {this.execCommand("superscript");}.bind(this) , "comptextarea_button_r"],
			justifyleft: [ "Justify Left", "toolbar/ed_align_left.gif", false, function(cmdID,UI,param) {this.execCommand("justifyleft");}.bind(this) , "comptextarea_button_l"],
			justifycenter: [ "Justify Center", "toolbar/ed_align_center.gif", false, function(cmdID,UI,param) {this.execCommand("justifycenter");}.bind(this) , "comptextarea_button_c"],
			justifyright: [ "Justify Right", "toolbar/ed_align_right.gif", false, function(cmdID,UI,param) {this.execCommand("justifyright");}.bind(this) , "comptextarea_button_r"],
			justifyfull: [ "Justify Full", "toolbar/ed_align_justify.gif", false, function(cmdID,UI,param) {this.execCommand("justifyfull");}.bind(this) , "comptextarea_button_c"],
			orderedlist: [ "Ordered List", "toolbar/ed_list_num.gif", false, function(cmdID,UI,param) {this.execCommand("insertorderedlist");}.bind(this) , "comptextarea_button_l"],
			unorderedlist: [ "Bulleted List", "toolbar/ed_list_bullet.gif", false, function(cmdID,UI,param) {this.execCommand("insertunorderedlist");}.bind(this) , "comptextarea_button_r"],
			outdent: [ "Decrease Indent", "toolbar/ed_indent_less.gif", false, function(cmdID,UI,param) {this.execCommand("outdent");}.bind(this) , "comptextarea_button_l"],
			indent: [ "Increase Indent", "toolbar/ed_indent_more.gif", false, function(cmdID,UI,param) {this.execCommand("indent");}.bind(this) , "comptextarea_button_r"],
			lefttoright: [ "Direction left to right", "toolbar/ed_left_to_right.gif", false, function(cmdID,UI,param) {this.execCommand("lefttoright");}.bind(this) , "comptextarea_button_l"],
			righttoleft: [ "Direction right to left", "toolbar/ed_right_to_left.gif", false, function(cmdID,UI,param) {this.execCommand("righttoleft");}.bind(this) , "comptextarea_button_r"],
			removeformat: [ "Remove formatting", "toolbar/ed_rmformat.gif", false, function(cmdID,UI,param) {this.execCommand("removeformat");}.bind(this) , "comptextarea_button_n"],
			setforecolor: [ "Font Color", "toolbar/ed_color_fg.gif", false, function(cmdID,UI,param) {this.execCommand("setforecolor");}.bind(this) , "comptextarea_button_l"],
			sethilitecolor: [ "Background Color", "toolbar/ed_color_bg.gif", false, function(cmdID,UI,param) {this.execCommand("sethilitecolor");}.bind(this) , "comptextarea_button_c"],
			forecolor: [ "Select Font Color", "toolbar/ed_arrow.gif", false, function(cmdID,UI,param) {this.execCommand("forecolor");}.bind(this) , "comptextarea_button_a"],
			hilitecolor: [ "Select Background Color", "toolbar/ed_arrow_right.gif", false, function(cmdID,UI,param) {this.execCommand("hilitecolor");}.bind(this) , "comptextarea_button_a"],
			inserthorizontalrule: [ "Horizontal Rule", "toolbar/ed_hr.gif", false, function(cmdID,UI,param) {this.execCommand("inserthorizontalrule");}.bind(this) , "comptextarea_button_n"],
			inserttable: [ "Insert Table", "toolbar/ed_insert_table.gif", false, function(cmdID,UI,param) {this.execCommand("inserttable");}.bind(this) , "comptextarea_button_l"],
			tablemenu: [ "Table Menu", "toolbar/ed_arrow_right.gif", false, function(cmdID,UI,param) {this.execCommand("tablemenu");}.bind(this) , "comptextarea_button_a"],
			createlink: [ "Insert Web Link", "toolbar/ed_link.gif", false, function(cmdID,UI,param) {this.execCommand("createlink", true);}.bind(this) , "comptextarea_button_l"],
			unablelink: [ "Unable Link", "toolbar/ed_unablelink.gif", false, function(cmdID,UI,param) {this.execCommand("unlink", false);}.bind(this) , "comptextarea_button_r"],
			insertimage: [ "Insert/Modify Image", "toolbar/ed_image.gif", false, function(cmdID,UI,param) {this.execCommand("insertimage");}.bind(this) , "comptextarea_button_l"],
			inserttex: [ "Insert Tex", "toolbar/ed_insert_tex.gif", false, function(cmdID,UI,param) {this.execCommand("inserttex");}.bind(this) , "comptextarea_button_n"],
			insertupload: [ "Insert Upload", "toolbar/ed_insert_upload.gif", false, function(cmdID,UI,param) {this.execCommand("insertupload");}.bind(this) , "comptextarea_button_r"],
			insertsmiley: [ "Insert Smiley", "toolbar/ed_emotions.gif", false, function(cmdID,UI,param) {this.execCommand("insertsmiley");}.bind(this) , "comptextarea_button_n"],
			savezip: [ "Save Zip", "toolbar/ed_savezip.gif", false, function(cmdID,UI,param) {this.execCommand("savezip");}.bind(this) , "comptextarea_button_n"]
		};
		
		for (var i in this.config.btnList) {
			if(this.config.btnList[i][1] != undefined) {
				var btn = this.config.btnList[i];
				btn[1] = _js_url + "/include/comp/textarea/images/" + btn[1];
				if (typeof compTextareaLang != "undefined" && typeof compTextareaLang.icons[i] != "undefined") {
					btn[0] = compTextareaLang.icons[i];
				}
			}
		}
	},
	// updates the state of a toolbar element.  This function is member of
	// a toolbar element object (unnamed objects created by createButton or
	// createSelect functions below).
	setButtonStatus: function(id, newval) {
		var oldval = this[id];
		var el = this.element;
		if (oldval != newval) {
			if(Element.hasClassName(el.parentNode, "comptextarea_button_n")) var class_name = "comptextarea_button_n";
			else if(Element.hasClassName(el.parentNode, "comptextarea_button_l")) var class_name = "comptextarea_button_l";
			else if(Element.hasClassName(el.parentNode, "comptextarea_button_c")) var class_name = "comptextarea_button_c";
			else if(Element.hasClassName(el.parentNode, "comptextarea_button_r")) var class_name = "comptextarea_button_r";
			else if(Element.hasClassName(el.parentNode, "comptextarea_button_a")) var class_name = "comptextarea_button_a";
			switch (id) {
			    case "enabled":
				if (newval) {
					Element.removeClassName(el.parentNode, class_name+"Disabled");
					el.disabled = false;
				} else {
					Element.addClassName(el.parentNode, class_name+"Disabled");
					el.disabled = true;
				}
				break;
			    case "active":
				if (newval) {
					Element.addClassName(el.parentNode, class_name+"Pressed");
				} else {
					Element.removeClassName(el.parentNode, class_name+"Pressed");
				}
				break;
			}
			this[id] = newval;
		}
	}, 
	// END of function: setButtonStatus
	createToolbar: function() {
		var table = null;
		var tb_row = null;
		//var execCommand = this.execCommand;
		var toolbar = this.toolbar;
		var tb_objects = new Object();
		this.toolbarObjects = tb_objects;
		var doc = document.createDocumentFragment();

		var change_el = null;
		
		//block = document.createElement('DIV');
		//block.className = 'toolBar';
		//block.unselectable = "on";
		//block.style.width = 'auto';
		//(block.style.styleFloat) ? block.style.styleFloat = 'left' : block.style.cssFloat = 'left';
		
		//var tmpDIV = block.cloneNode(false);

		// creates a new line in the toolbar
		function newLine(doc) {
			var table = document.createElement("table");
			table.border = "0px";
			table.cellSpacing = "0px";
			table.cellPadding = "0px";
			table.className = "comptextarea_toolbar";
			//Element.addClassName(table,"comptextarea_toolbar");
			// TBODY is required for IE, otherwise you don't see anything
			// in the TABLE.
			var tb_body = document.createElement("tbody");
			table.appendChild(tb_body);
			var tb_row = document.createElement("tr");
			tb_body.appendChild(tb_row);
			doc.appendChild(table);
			
			return new Array(table, tb_row)
		}; // END of function: newLine
		// this function will handle creation of combo boxes.  Receives as
		// parameter the name of a button as defined in the toolBar config.
		// This function is called from createButton, above, if the given "txt"
		// doesn't match a button.
		function createSelect(txt) {
			var options = null;
			var el = null;
			var cmd = null;
			var customSelects = this.config.customSelects;
			var context = null;
			var tooltip = "";
			switch (txt) {
			    case "fontsize":
			    case "fontname":
			    case "formatblock":
				// the following line retrieves the correct
				// configuration option because the variable name
				// inside the Config object is named the same as the
				// button/select in the toolbar.  For instance, if txt
				// == "formatblock" we retrieve config.formatblock (or
				// a different way to write it in JS is
				// config["formatblock"].
				options = this.config[txt];
				cmd = txt;
				break;
			    default:
				// try to fetch it from the list of registered selects
				cmd = txt;
				var dropdown = customSelects[cmd];
				if (typeof dropdown != "undefined") {
					options = dropdown.options;
					context = dropdown.context;
					if (typeof dropdown.tooltip != "undefined") {
						tooltip = dropdown.tooltip;
					}
				} else {
					alert("ERROR [createSelect]:\nCan't find the requested dropdown definition");
				}
				break;
			}
			if (options) {
				el = document.createElement("select");
				el.title = tooltip;
				var obj = {
					name	: txt, // field name
					element : el,	// the UI element (SELECT)
					enabled : true, // is it enabled?
					text	: false, // enabled in text mode?
					cmd	: cmd, // command ID
					state	: this.setButtonStatus, // for changing state
					context : context
				};
				tb_objects[txt] = obj;
				
				for (var i in options) {
					var op = document.createElement("option");
					op.innerHTML = i;
					op.value = options[i];
					el.appendChild(op);
				}
				if(browser.isSafari) {
					//Safariのfontsizeに対応するため
					//もう少し簡単な方法があるかも
					Event.observe(el, "mousedown", function () {
						this.execCommand("bold", false, undefined);
						//var el = this.getParentElement();
						var sel = this.getSelection();
						var range = this.createRange(sel);
						var el_ac = sel.anchorNode;
						var el_fc =sel.focusNode;
						
						if(el_ac || el_fc) {
							if(el_fc) var el = this.getParentElementByTagName(el_fc, "span");
							if(el.style.fontWeight != "bold" && el_ac) {
								if(el_ac) el = this.getParentElementByTagName(el_ac, "span");
							}
							if(el) {
								el.style.fontWeight = "";
								this.sizeElement = el;
							}
						}
					}.bindAsEventListener(this),false, this.id);
				}
				Event.observe(el, "change", function () {
					this.comboSelected(el, txt);
				}.bindAsEventListener(this),false, this.id);
			}
			return el;
		}; // END of function: createSelect
		// appends a new button to toolbar
		function createButton(text, class_name) {
			var el = null;
			var btn = null;
			var tb_cell = null;
			switch (text) {
				case "linebreak":
					var ret = newLine(doc);
					table = ret[0];
					tb_row = ret[1];
					return false;
				case "separator":
					el = document.createElement("div");
					el.className = "comptextarea_separator";
					//Element.addClassName(el,"comptextarea_separator");
					break;
				//case "separator_block":
				//	el = document.createElement("div");
				//	Element.addClassName(el,"comptextarea_separator_block");
				//	break;
			    case "space":
					el = document.createElement("div");
					el.className = "comptextarea_space";
					//Element.addClassName(el,"comptextarea_space");
					break;
				default:
					btn = this.config.btnList[text];
			}
			if (!el && btn) {
				var el = document.createElement("IMG");
				//el.align = 'absbottom';
				el.src = btn[1];
				el.unselectable = 'on';
				//el.enableInHTML = enabled;
				el.className = "comptextarea_"+text;
				//Element.addClassName(el,"comptextarea_"+text);
				el.title = btn[0];
				el.alt = btn[0];
				
				var obj = {
					name	: text, // the button name (i.e. 'bold')
					element : el, // the UI element (DIV)
					enabled : true, // is it enabled?
					active	: false, // is it pressed?
					text	: btn[2], // enabled in text mode?
					cmd	: btn[3], // the command ID
					state	: this.setButtonStatus, // for changing state
					context : btn[4] || null // enabled in a certain context?
				};

				tb_objects[text] = obj;
				//イベント追加
				// handlers to emulate nice flat toolbar buttons
				if(!el.src.match(/ed_arrow/)) {
					Event.observe(el, "mouseover", function () {
						if (obj.enabled && Element.addClassName) {
							Element.addClassName(el.parentNode,class_name+"Hover");
						}
					},false, this.id);
					Event.observe(el, "mouseout", function () {
						if (obj.enabled && Element.removeClassName) {
							Element.removeClassName(el.parentNode, class_name+"Hover");
							Element.removeClassName(el.parentNode, class_name+"Active");
						}
					},false, this.id);
					Event.observe(el, "mousedown", function (event) {
						if (obj.enabled) {
							Element.addClassName(el.parentNode, class_name+"Active");
							Element.removeClassName(el.parentNode, class_name+"Pressed");
							Event.stop(event);
						}
					},false, this.id);
				} else {
					Event.observe(el, "mousedown", function (event) {
						if (obj.enabled) {
							Event.stop(event);
						}
					},false, this.id);
				}
				Event.observe(el, "click", function (event) {
					if (obj.enabled) {
						Element.removeClassName(el.parentNode, class_name+"Active");
						Element.removeClassName(el.parentNode, class_name+"Hover");
						obj.cmd(this, obj.name, obj);
						Event.stop(event);
					}
				}.bindAsEventListener(this),false, this.id);
			} else if (!el) {
				el = createSelect.bind(this)(text);
			}
			if (el) {
				tb_cell = document.createElement("td");
				if(el.tagName.toLowerCase() == "img") {
					tb_cell.className = class_name;
					//Element.addClassName(tb_cell,class_name);
				}
				//tb_row.appendChild(tb_cell);
				tb_cell.appendChild(el);
				//if(!(browser.isIE || browser.isOpera)) {
				//	if(table.offsetWidth > toolbar.offsetWidth)
				//		toolbar.style.width = table.offsetWidth + "px";
				//}
			} else {
				alert("FIXME: Unknown toolbar item: " + text);
			}
			
			return tb_cell;
		};
		var ret = newLine(doc);
		table = ret[0];
		tb_row = ret[1];
		var first = true;
		for (var i = 0, confLen = this.config.toolbar.length; i < confLen; i++) {
			if (!first) {
				var tb_cell = createButton.bind(this)("linebreak");
				if(tb_cell) tb_row.appendChild(tb_cell);
			} else {
				first = false;
			}
			var group = this.config.toolbar[i];
			for (var j = 0, groupLen = group.length; j < groupLen; j++) {
				var code = group[j];
				if(this.config.btnList[code]) {
					var tb_cell = createButton.bind(this)(code, this.config.btnList[code][4]);
					if(tb_cell) tb_row.appendChild(tb_cell);
				} else {
					var tb_cell = createButton.bind(this)(code);
					if(tb_cell) tb_row.appendChild(tb_cell);
				}
			}
		}
		toolbar.appendChild(doc);
	},
	handleEvent: function(event) {
		if(browser.isSafari) {
			this.preSel = this.getSelection();
			this.preRange = this.createRange(this.preSel);
		}
		
		var keyEvent = ((browser.isIE || browser.isOpera) && event.type == "keydown") || (!(browser.isIE || browser.isOpera) && event.type == "keypress");
		if (keyEvent && event.ctrlKey && !event.altKey) {
			//Ctrl+処理
			//ショートカットボタン
			var sel = null;
			var range = null;
			var key = String.fromCharCode((browser.isIE || browser.isOpera) ? event.keyCode : event.charCode).toLowerCase();
			var cmd = null;
			var value = null;
			switch (key) {
			    case 'a':
				if (!(browser.isIE)) {
					// KEY select all
					sel = this.getSelection();
					sel.removeAllRanges();
					range = this.createRange();
					range.selectNodeContents(this.text_content.body);
					sel.addRange(range);
					Event.stop(event);
				}
				break;

				// simple key commands follow

			    case 'b': cmd = "bold"; break;
			    case 'i': cmd = "italic"; break;
			    case 'u': cmd = "underline"; break;
			    case 's': cmd = "strikethrough"; break;
			    case 'l': cmd = "justifyleft"; break;
			    case 'e': cmd = "justifycenter"; break;
			    case 'r': cmd = "justifyright"; break;
			    case 'j': cmd = "justifyfull"; break;
			    case 'z': cmd = "undo"; break;
			    case 'y': cmd = "redo"; break;
			    case 'v': if ((browser.isIE || browser.isOpera) || this.config.htmlareaPaste) { cmd = "paste"; } break;
			    case 'n': cmd = "formatblock"; value = (browser.isIE || browser.isOpera) ? "<div>" : "div"; break;

			    case '0': cmd = "killword"; break;

				// headings
			    case '1':
			    case '2':
			    case '3':
			    case '4':
			    case '5':
			    case '6':
				cmd = "formatblock";
				value = "h" + key;
				if ((browser.isIE || browser.isOpera))
					value = "<" + value + ">";
				break;
			}
			if (cmd) {
				// execute simple command
				this.execCommand(cmd, false, value);
				Event.stop(event);
			}
		}else {
			switch (event.type) {
				case "mouseup":
					this.execCommand("addundolevel");
					//Event.stop(event);
					break;
				case "keyup":
					/*var sel = this.getSelection();
					var range = this.createRange(sel);
					if (event.keyCode == 13){
						
						if(!range.pasteHTML) {
							this.execCommand("addundolevel");
						}
					}*/
					//Event.stop(event);
					/*
					if(event.keyCode == 13 && (event.shiftKey == false)) {
						var el = this.getParentElement();
						if(el.tagName == "BLOCKQUOTE") {
							this.text_content.execCommand("outdent", false, value);
						} else if(el.parentNode.tagName == "BLOCKQUOTE"){
							this.text_content.execCommand("outdent", false, value);
						}
					}
					*/
					break;
				case "keydown":
				
					var sel = this.getSelection();
					if (sel.type == "Control") {
						return;
					}
					var range = this.createRange(sel);
					//if (event.keyCode == 13 && !event.shiftKey){
					if (event.keyCode == 13 && (event.shiftKey == false)){
						if(browser.isIE) {
							this.execCommand("foce_addundolevel");
							var el = this.getParentElement();
							//if((el.tagName == "HTML") || (el.tagName == "BODY") || (el.tagName == "P") || (el.tagName == "TD") || (el.tagName == "THEAD") || (el.tagName == "TFOOT") || (el.tagName == "DIV") || (el.tagName == "FONT") || (el.tagName == "STRONG")) {
							if((el.tagName != "LI")){
								if(el.innerHTML == "")
									range.pasteHTML("&nbsp;");
								var value = (browser.isIE || browser.isOpera) ? "<div>" : "div";
								this.execCommand("formatblock", false, value);
							}

							//this.execCommand("foce_addundolevel");
							/*if(range.pasteHTML) {
						    	range.pasteHTML("<br />");
								this.execCommand("addundolevel");
								range.collapse(false);
								if(range.select)
									range.select();
								Event.stop(event);
							}else{
								this.execCommand("foce_addundolevel");
							}*/
							
							//Event.stop(event);
							//return false;
							this.detachBlockQuoteIE();
							
						} else {
							this.execCommand("foce_addundolevel");
							this.detachBlockQuoteGecko();
						}
					}
					
					//KEY backspace delete
					else if(event.keyCode == 8 || event.keyCode == 46){
						this.execCommand("addundolevel");
					} else if(event.keyCode == 9 && browser.isGecko && !event.shiftKey){
						//Tab Next Element
						Element.getChildElement(this.htmlModeBtn).focus();
						Event.stop(event);
					}
					
					break;
			}
		}
		if(event.type == "keyup" || event.type == "mouseup") {
			//var el = Event.element(event);
			//this.el =el;
			
			//this.currentEvent = event;
			
			// update the toolbar state after some time
			if (this.timerToolbar) {
				clearTimeout(this.timerToolbar);
			}
			this.timerToolbar = setTimeout(function() {
				this.updateToolbar();
				//現在element取得
				this.el_array = this.getAllAncestors();
				this.timerToolbar = null;
			}.bind(this), 50);
		}
	},
	detachBlockQuoteIE: function() {
		var range = this.text_content.selection.createRange();
	    
	    var id_name = "split_buf";
	    var count = 0,buf_id_name = id_name;
	    while(this.text_content.getElementById(buf_id_name)) {
	        count += 1;
	        buf_id_name = id_name + count;
	    }
	    range.pasteHTML('<span id="' + buf_id_name + '"></span>');
	    var id_name_el = this.text_content.getElementById(buf_id_name);
	    
	    id_name_el.id = "";
	    var node_arr = this.scanParentNode(id_name_el.parentNode), bq_el = null;
	    for(var i = 0; i < node_arr.length; i++) {
	        var buf_el= node_arr[i];
	        if(buf_el.tagName == "BLOCKQUOTE" && Element.hasClassName(buf_el, "quote")) {
	            bq_el = buf_el;
	        }
	    }
	    if(bq_el) {
	        var clone_el = id_name_el.cloneNode(false);
	        var new_text_nd = this.cloneTextElement(id_name_el, clone_el, bq_el);
	        if(!bq_el.nextSibling) {
	            bq_el.parentNode.appendChild(new_text_nd);
	        } else {
	            bq_el.parentNode.insertBefore(new_text_nd, bq_el.nextSibling);
	        }
	        var br_el = this.text_content.createElement("BR");
	        bq_el.parentNode.insertBefore(br_el, new_text_nd);
	        var div_el = this.text_content.createElement("DIV");
	        bq_el.parentNode.insertBefore(div_el, br_el);
	        div_el.innerHTML="&nbsp;";
	        range.move("character",2);
	        range.select();
	        div_el.innerHTML="";
	        id_name_el.removeNode(true);
	    }
	    id_name_el.removeNode(true);
	},
	detachBlockQuoteGecko: function() {
		var sel = this.getSelection();
		var range = this.createRange(sel);
					
		var cpRange = range.cloneRange();
		var stNode = sel.anchorNode;
		var node_arr = this.scanParentNode(stNode.parentNode);
		var bq_el = null;
		
		for(var i=0;i<node_arr.length;i++) {
	        var buf_el = node_arr[i];
	        if(buf_el.tagName=="BLOCKQUOTE" && Element.hasClassName(buf_el, "quote")) {
	            bq_el = buf_el;
	        }
	    }
		var text_nd,nd_flag = false;
	    if(bq_el)
	    {
	        if(stNode.nodeType == 3) {
	        	//text Node:テキスト分割
	            text_nd = stNode.splitText(sel.anchorOffset);
	        } else {
	            nd_flag = true;
	        }
	    } else {
	        if(stNode.tagName == "BLOCKQUOTE" && Element.hasClassName(stNode, "quote")) {
	            bq_el = stNode;
	            nd_flag = true;
	        }
	    }
	    if(nd_flag) {
	        stNode = this.text_content.createTextNode("");
	        cpRange.insertNode(stNode);
	        text_nd = this.text_content.createTextNode("");
	        cpRange.insertNode(text_nd)
	    }
	    if(bq_el) {
	        var new_text_nd = this.cloneTextElement(stNode,text_nd,bq_el);
	        if(!bq_el.nextSibling) {
	            bq_el.parentNode.appendChild(new_text_nd)
	        } else {
	            bq_el.parentNode.insertBefore(new_text_nd, bq_el.nextSibling)
	        }
	        //分割したblockquote_el次にdiv-br-nbsp;挿入
	        var br_el = this.text_content.createElement("BR");
	        bq_el.parentNode.insertBefore(br_el, new_text_nd);
	        var div_el = this.text_content.createElement("DIV");
	        div_el.innerHTML = "&nbsp;";
	        bq_el.parentNode.insertBefore(div_el, br_el);
	        sel.collapse(div_el, 0);
	    }
	},
	scanParentNode: function(el) {
	    var node_arr=[];
	    while(el && el.nodeType==1 && el.tagName != "BODY") {
	        node_arr[node_arr.length] = el;
	        el = el.parentNode;
	    }
	    return node_arr;
	},
	cloneTextElement: function(node_el, text_el, bq_el) {
	    while(node_el != bq_el)
	    {
	        var parent_el = node_el.parentNode;
	        if(!parent_el) {
	            return false;
	        }
	        var clone_el = parent_el.cloneNode(false);
	        clone_el.appendChild(text_el);
	        var next_el = node_el.nextSibling;
	        while(next_el != null) {
	            parent_el.removeChild(next_el);
	            clone_el.appendChild(next_el);
	            next_el = node_el.nextSibling;
	        }
	        node_el = parent_el;
	        text_el = clone_el;
	    }
	    return text_el;
	},
	updateToolbar: function() {
		
		var text_content = this.text_content;
		var text = (this.editMode == "html");
		
		for (var i in this.toolbarObjects) {
			var btn = this.toolbarObjects[i];
			var cmd = i;
			var inContext = true;
			
			if (btn.element == undefined) {
				continue;
			}
			btn.state("enabled", (!text || btn.text) && inContext);
			if (typeof cmd == "function") {
				continue;
			}
			// look-it-up in the custom dropdown boxes
			var dropdown = this.config.customSelects[cmd];
			if ((!text || btn.text) && (typeof dropdown != "undefined")) {
				dropdown.refresh(this);
				continue;
			}
			switch (cmd) {
			    case "fontname":
			    case "fontsize":
			    case "formatblock":
					if (!text) try {
						var value = ("" + text_content.queryCommandValue(cmd)).toLowerCase();
						if (!value) {
							btn.element.selectedIndex = 0;
							break;
						}
						// HACK -- retrieve the config option for this
						// combo box.  We rely on the fact that the
						// variable in config has the same name as
						// button name in the toolbar.
						var options = this.config[cmd];
						var k = 0;
						for (var j in options) {
							// FIXME: the following line is scary.
							if ((j.toLowerCase() == value) ||
							    (options[j].substr(0, value.length).toLowerCase() == value)) {
								btn.element.selectedIndex = k;
								throw "ok";
							}
							++k;
						}
						btn.element.selectedIndex = 0;
					} catch(e) {};
				break;
			    case "htmlmode": btn.state("active", text); break;
			    case "lefttoright":
			    case "righttoleft":
					var el = this.getParentElement();
					while (el && !this.isBlockElement(el))
						el = el.parentNode;
					if (el)
						btn.state("active", (el.style.direction == ((cmd == "righttoleft") ? "rtl" : "ltr")));
					break;
				case "undo":
				case "redo":
				case "setforecolor":
				case "forecolor":
				case "createlink":
				case "sethilitecolor":
				case "hilitecolor":
				case "removeformat":
				case "inserttable":
				case "tablemenu":
				case "savezip":
				case "inserttex":
				case "insertsmiley":
				case "insertupload":
					// inserttable,insertupload,inserttex,insertsmiley等は判別できるように修正可能のはず
					btn.state("active", false);
					break;
				case "createlink":
				case "unablelink":
					// Get link
					var el = this.getParentElement();
					if(el) {
						var anchorLink = this.getParentElementByTagName(el, "a", "href");
						if (anchorLink) {
							btn.state("active", true);
						} else {
							btn.state("active", false);
						}
					} else {
						btn.state("active", false);
					}
					break;
				default:
					cmd = cmd.replace(/(un)?orderedlist/i, "insert$1orderedlist");
					try {
						btn.state("active", (text_content.queryCommandState(cmd)));
						//btn.state("active", (!text && text_content.queryCommandState(cmd)));
					} catch (e) {}
			}
		}
	},
	createRange: function(sel) {
		if((browser.isIE || browser.isOpera)) {
			return sel.createRange();
		//} else if(browser.isSafari && !sel.getRangeAt) {
		//	return '' + this.text.contentWindow.getSelection();
		} else {
			if (typeof sel != "undefined"){
				try {
					return sel.getRangeAt(0);
				} catch(e) {
					return this.text_content.createRange();
				}
			}else {
				return this.text_content.createRange();
			}
		}
	},
	getSelection: function() {
		return this.text_content.selection ? this.text_content.selection : this.text.contentWindow.getSelection();
	},
	undo: function() {
		if (this.custom_undo_redo_levels >= 0) {
			this.execCommand("addundolevel");
			var txt = this.undoLevels[--this.custom_undo_redo_levels];

			if (txt) this.text_content.body.innerHTML = txt;
			else ++this.custom_undo_redo_levels;
		}
	},
	redo: function() {
		if (this.custom_undo_redo_levels < this.undoLevels.length - 1) {
			var txt = this.undoLevels[++this.custom_undo_redo_levels];
			if (txt) this.text_content.body.innerHTML = txt;
			else --this.custom_undo_redo_levels;
		}
	},
	// Called when the user clicks the color arrow button
	showColorDialog: function(cmdID, el, img_el, parent_id) {
		if(cmdID == "forecolor" || cmdID == "hilitecolor") {
			var img_el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_set"+cmdID);
			this.change_el = { 	el: el, 
								img_el: img_el
							 }
		} else {
			this.change_el = { 	el: el, 
								img_el: img_el
							 }
		}
		if(cmdID == "forecolor" || cmdID == "hilitecolor") {
			var offset = [0, 0];
		} else {
			var popup_el = $(this.popup[this.popupPrefix + this.id + parent_id].popupID);
			var offset = Position.cumulativeOffset(popup_el);
		}
		this.showDialogBox(cmdID, "comp_textarea_view_selectcolor", el, false, offset);
	},
	// Called when the user clicks the Insert Table button
	showTableDialog: function(el) {
		this.showDialogBox("inserttable", "comp_textarea_view_inserttable", el);
	},
	// Called when the user clicks the TableMenu button
	showTableMenuDialog: function(el) {
		this.showDialogBox("tablemenu", "comp_textarea_view_tablemenu", el);
	},
	// Called when the user clicks the TableMerge button
	showTableMergeDialog: function(td) {
		this.closePopup("tablemenu");
		this.closePopup("tableinsertmenu");
		
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_inserttable");
		this.showDialogBox("tablemerge", "comp_textarea_view_tablemerge", el);
	},
	// Called when the user clicks the TableOperation button
	showTableOperationDialog: function() {
		var el = $(this.popup[this.popupPrefix + this.id + "tablemenu"].popupID);
		this.showDialogBox("tableinsertmenu", "comp_textarea_view_tableinsertmenu", el, true);
	},
	insertImageDialog: function(image) {
		if (typeof image == "undefined") {
			image = this.getParentElement();
			if (image && !/^img$/i.test(image.tagName))
				image = null;
		}
		if (image) {
			var border = valueParseInt(Element.getStyle(image, "borderWidth"));
			if(typeof image.style.cssFloat != "undefined") {
    			var float_value = image.style.cssFloat;
    		} else {
    			var float_value = image.style.styleFloat;
    		}
	    	if(float_value == "left" || float_value == "right") {
	    		var align = float_value;
	    	} else {
	    		var align = image.align; 
	    	}
    	
			this.imageProperty = {
				f_base   : '',
				f_url    : (browser.isIE || browser.isOpera) ? image.src : image.getAttribute("src"),
				f_alt    : image.alt.strip(),
				f_align  : align,
				f_border : (border <= 0) ? '' : border,
				f_vert   : (image.vspace <= 0) ? '' : image.vspace,
				f_horiz  : (image.hspace <= 0) ? '' : image.hspace,
				f_width  : image.offsetWidth,
				f_height : image.offsetHeight
			};
		} else {
			//初期化
			this.imageProperty  = {
				f_base   : '',
				f_url    : '',
				f_alt    : '',
				f_border : '',
				f_align  : '',
				f_vert   : '',
				f_horiz  : '',
				f_width  : '',
				f_height : ''
			};
		}
		this.el = image;
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_insertimage");
		this.showDialogBox("insertimage", "comp_textarea_view_insertimage", el);
	},
	insertTexDialog: function(image) {
		if (typeof image == "undefined") {
			image = this.getParentElement();
			if(image) {
				image = this.getParentElementByTagName(image, "image", "src");
			}
		}
		if (image) {
			if (/^img$/i.test(image.tagName)) {
				this.texProperty = {
					f_texexp : (browser.isIE || browser.isOpera) ? image.src : image.getAttribute("src")
				};
			} else {
				var str = this.createRange(this.getSelection());
				str = (browser.isIE || browser.isOpera) ? str.text : String(str);
				this.texProperty = {
					f_texexp : str.replace(/\n/g, '')
				};
			}
		} else {
			image = null;
			// 初期化
			this.texProperty  = {
				f_texexp : ''
			};
		}
		this.el = image;
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_inserttex");
		this.showDialogBox("inserttex", "comp_textarea_view_inserttex", el);
	},
	insertSmileyDialog: function(el) {
		this.showDialogBox("insertsmiley", "comp_textarea_view_insertsmiley", el);
	},
	createLinkDialog: function(link) {
		if (typeof link == "undefined") {
			link = this.getParentElement();
			if (link) {
				//if (/^img$/i.test(link.tagName))
				//	link = link.parentNode;
				if (link && !/^a$/i.test(link.tagName))
					link = null;
			}
		}
		if (!link) {
		var sel = this.getSelection();
			/*
			var sel = this.getSelection();
			var range = this.createRange(sel);
			var compare = 0;
			if ((browser.isIE || browser.isOpera)) {
				if(sel.type == "Control")
					compare = range.length;
				else
					compare = range.compareEndPoints("StartToEnd", range);
			} else {
				compare = range.compareBoundaryPoints(range.START_TO_END, range);
			}
			if (compare == 0) {
				if (typeof compTextareaLang.msg["selectlink_error"] == "undefined") 
					alert("You need to select some text before creating a link");
				else
					alert(compTextareaLang.msg["selectlink_error"]);
			
				return;
			}
			*/
			this.linkProperty = {
				f_href : '',
				f_title : '',
				f_target : '',
				f_usetarget : true
			};
		} else {
			this.linkProperty = {
				f_href   : (browser.isIE || browser.isOpera) ? link.href : link.getAttribute("href"),
				f_title  : link.title,
				f_target : link.target,
				f_usetarget : true
			};
		}
		this.el = link;
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_createlink");
		this.showDialogBox("createlink", "comp_textarea_view_createlink", el);
	},
	insertUploadDialog: function(link) {
		this.el = null;
		if (typeof link == "undefined") {
			link = this.getParentElement();
			if (link) {
				if (link && !/^a$/i.test(link.tagName))
					link = null;
			}
		}
		this.el = link;
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_" + "insertupload");
		this.showDialogBox("insertupload", "comp_textarea_view_insertupload", el);
		
	},
	setColor: function(cmdID, param) {
		var color = null;
		if(param.color != '' && param.color != '#') {
			color = param.color.toLowerCase();
		}
		if (color) { // selection not canceled
			this.closePopup(cmdID);
			if(cmdID == "hilitecolor") { (browser.isIE || browser.isOpera|| browser.isSafari) && (cmdID = "backcolor");}
			if(cmdID == "forecolor" || cmdID == "hilitecolor" || cmdID == "backcolor"){
				//親選択
				if(this.preRange.select) this.preRange.select();
				this.text_content.execCommand(cmdID, false, color);
			}else {
				this.change_el.el.value = color;
			}
			this.change_el.img_el.style.backgroundColor = color;
		}
	},
	insertTable: function(param) {
		//テーブルプロパティダイアログ検索
		if(this.popup[this.popupPrefix + this.id + "edittable"]) {
			var el = $(this.popup[this.popupPrefix + this.id + "edittable"].popupID);
		}
		//var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_edittable");
		//プロパティセット
		if(el != undefined ) {
			ret = this.setDialogProperty(el);
			if(!ret)
				return false;
		}
		//ダイアログを閉じる
		this.closePopup("inserttable");
		
		//テーブル作成
		if(typeof param != "undefined") {
			//親選択
			if(this.preRange.select)
				this.preRange.select();
			
			this.focusEditor();
			
			var row = param.f_rows;
			var col = param.f_cols;

			var sel = this.getSelection();
			var range = this.createRange(sel);
			var text_content = this.text_content;
			// create the table element
			var table = text_content.createElement("table");
			
			// assign the given arguments
			for (var field in this.tableProperty) {
				var value = this.tableProperty[field];
				if (!value) {
					continue;
				}
				switch (field) {
				    case "f_width"   :
						if(value=="")
							this.tableProperty.f_w_unit = "";
						table.style.width = (value + this.tableProperty.f_w_unit); break;
						break;
					case "f_height"  : 
						if(value=="")
							this.tableProperty.f_h_unit = "";
						table.style.height = value + this.tableProperty.f_h_unit; break;
						break;
				    case "f_align"   : table.align	 = value; break;
				    case "f_border"  : 
						table.border = parseInt(value);
						if(parseInt(value) == 0)
							table.style.border = "1px dotted #666666";
						else if(this.tableProperty.f_border_style !="" || this.tableProperty.f_border_color !=""){
							table.style.borderColor = this.tableProperty.f_border_color;
							table.style.borderStyle = this.tableProperty.f_border_style;
							table.style.borderWidth = parseInt(value)+"px";
						}
						break;
				    case "f_spacing" : table.cellSpacing = parseInt(value); break;
				    case "f_padding" : table.cellPadding = parseInt(value); break;
					case "f_background" : 
						if(value!="")
							table.style.backgroundColor=value;
						break;
					case "f_collapse" :
						if(value)
							table.style.borderCollapse = "collapse";
						break;
					case "f_horiz" :
						if(value) {
							table.style.marginLeft = parseInt(value) + "px";
							table.style.marginRight = parseInt(value) + "px";
						}
						break;
					case "f_vert" :
						if(value) {
							table.style.marginTop = parseInt(value) + "px";
							table.style.marginBottom = parseInt(value) + "px";
						}
						break;
				}
			}
			
			var cellwidth = 0;
			if (this.tableProperty.f_fixed)
				cellwidth = Math.floor(100 / parseInt(col));
			var tbody = text_content.createElement("tbody");
			table.appendChild(tbody);
			for (var i = 0; i < row; ++i) {
				var tr = text_content.createElement("tr");
				tbody.appendChild(tr);
				for (var j = 0; j < col; ++j) {
					var td = text_content.createElement("td");
					var td_style = td.style;
					if(this.tableProperty.f_border == 0)
						td_style.border = "1px dotted #666666";
					else if(this.tableProperty.f_border_style !="" || this.tableProperty.f_border_color !=""){
						td_style.borderColor = this.tableProperty.f_border_color;
						td_style.borderStyle = this.tableProperty.f_border_style;
						td_style.borderWidth = parseInt(this.tableProperty.f_border)+"px";
						//table.style.border	 = parseInt(this.tableProperty.f_border)+"px"+ this.tableProperty.f_border_style + this.tableProperty.f_border_color;
					}
					if (cellwidth) {
						td_style.width = cellwidth + "%";
					}
					tr.appendChild(td);
					// Mozilla likes to see something inside the cell.
					//(browser.isGecko) && td.appendChild(text_content.createElement("br"));
					if (browser.isGecko) {
						td.innerHTML = td.innerHTML + "&nbsp;";
					}
				}
			}
			if (browser.isIE) {
				range.pasteHTML(table.outerHTML);
				range.pasteHTML("<div> </div>");
			} else {
				// insert the table
				this.insertNodeAtSelection(table);
			}
			
			return true;
		}
	},
	insertImage: function(params) {
		this.closePopup("insertimage");
		this.closePopup("insertsmiley");
		
		//親選択
		if(this.preRange.select) {
			this.preRange.select();
		}
		
		this.focusEditor();

		if (!params) {	// user must have pressed Cancel
			return false;
		}
		
		if(this.el && this.el.tagName.toLowerCase() == 'img') {
			var img = this.el;
		} else {
			var img = "";
		}
		if (!img) {
			var sel = this.getSelection();
			var range = this.createRange(sel);
			if(!browser.isSafari) {
				this.text_content.execCommand("insertimage", false, params.f_url);
				if (browser.isIE || browser.isOpera) {
					img = range.parentElement();
					// wonder if this works...
					if (img.tagName.toLowerCase() != "img") {
						img = img.previousSibling;
					}
				} else {
					if (range.startContainer.nodeType == 1) {
						img = range.startContainer.childNodes[range.startOffset];
					} else {
						img = range.startContainer.previousSibling;
						if (!img || !img.tagName || img.tagName.toLowerCase() != "img") {
							img = range.startContainer.nextSibling;
						}
					}
				}
			} else {
				//Safari
				img = this.insertImageSafari(params.f_url);
			}
		} else {
			img.src = params.f_url;
		}
		for (var field in params) {
			var value = params[field];
			value = value.strip();
			switch (field) {
				case "f_url"    : img.src	= value; break;			//日本語名称対応のため追加
				case "f_title"    : img.title	= value; break;
			    case "f_alt"    : img.alt = value; break;
			    case "f_border" : Element.setStyle(img, {"border":parseInt(value || "0")+"px solid #cccccc"}); break;		/* img.border = parseInt(value || "0"); */
			    case "f_align"  : 
			    	//align処理は最後で行う
			    	break;
			    case "f_vert"   : img.vspace = parseInt(value || "0"); break;
			    case "f_horiz"  : img.hspace = parseInt(value || "0"); break;
			    case "f_width"   : img.style.width =  (value=='' || value=='0') ? '' : parseInt(value || "0") + "px"; break;
			    case "f_height"  : img.style.height = (value=='' || value=='0') ? '' : parseInt(value || "0") + "px"; break;
			}
		}
		var value = params["f_align"];
		if(value == "") {
    		if(typeof img.style.cssFloat != "undefined") {
    			img.style.cssFloat = "none";
    		} else {
    			img.style.styleFloat = "none";
    		}
    	}
    	if(value == "left" || value == "right") {
    		if(typeof img.style.cssFloat != "undefined") {
    			img.style.cssFloat = value;
    		} else {
    			img.style.styleFloat = value;
    		}
    	} else {
    		img.align	 = value; 
    	}
	},
	insertUpload: function(params) {
		this.closePopup("insertupload");
		//親選択
		if(this.preRange.select)
			this.preRange.select();
		
		this.focusEditor();
		
		if (!params) {	// user must have pressed Cancel
			return false;
		}
		
		if (this.el && this.el.tagName.toLowerCase() == 'a') {
			var a = this.el;
		} else {
			var a = "";
		}
		
		if (a) {
			this.selectNodeContents(a);
			this.text_content.execCommand("unlink", false, null);
		}
		var sel = this.getSelection();
		var range = this.createRange(sel);
		//var text_content = this.text_content;
		//var insert = text_content.createElement("span");
		//insert.innerHTML = params;
		
		if (browser.isIE) {
			range.pasteHTML(params);
			//range.pasteHTML(insert.outerHTML);
		} else if(browser.isOpera) {
			//Operaの場合、rangeの位置に挿入ができない
			var p = this.getParentElement();
			var insert = this.text_content.createElement("span");
			insert.innerHTML = params;
			p.appendChild(a);
		} else if(browser.isSafari) {
			range.setStart(this.text_content.body, 0);
			range.setEnd(this.text_content.body, 0);
			var insert = range.createContextualFragment(params);
			if(this.startNode == this.endNode) {
				range.setStartAfter(this.startNode);
			} else {
				range.setStartBefore(this.startNode);
			}
			range.setEndAfter(this.endNode);
			if(this.startNode.tagName == "BR") {
				for (var i = insert.childNodes.length - 1; i >= 0; i--) {
					this.startNode.parentNode.insertBefore(insert.childNodes[i], this.startNode);
				}
			} else {
				range.insertNode(insert);
			}
		} else {
			var insert = range.createContextualFragment(params);
			this.insertNodeAtSelection(insert);
		}
	},
	insertTex: function(params) {
		this.closePopup("inserttex");
		//親選択
		if(this.preRange.select)
			this.preRange.select();
		
		this.focusEditor();

		if (!params) {	// user must have pressed Cancel
			return false;
		}
		
		if(this.el && this.el.tagName.toLowerCase() == 'img')
			var img = this.el;
		else
			var img = "";
		
		var texexp = params.f_texexp.replace(/\'/g, "&#039;");
		var texsrc = _js_url + "/include/comp/textarea/tex.php?c=" + encodeURIComponent(texexp).replace(/%/g, "%_");
		
		if (!img) {
			var sel = this.getSelection();
			var range = this.createRange(sel);
			if(!browser.isSafari) {
				this.text_content.execCommand("insertimage", false, texsrc);
				if (browser.isIE || browser.isOpera) {
					img = range.parentElement();
					// wonder if this works...
					if (img.tagName.toLowerCase() != "img") {
						img = img.previousSibling;
					}
				} else {
					if (range.startContainer.nodeType == 1) {
						img = range.startContainer.childNodes[range.startOffset];
					} else {
						img = range.startContainer.previousSibling;
					}
				}
			} else {
				//Safari
				img = this.insertImageSafari(texsrc);
			}
		} else {
			img.src = texsrc;
		}
		if (img) {
			//＜＞”等特殊文字が入力された際、エスケープしても化ける可能性が
			//あるのでとりあえず保留
			//img.alt = texexp;
			img.alt = "Tex";
			img.border = "0";
		}
	},
	//Safari
	insertImageSafari: function(src) {
		//var sel = this.getSelection();
		//var range = this.createRange(sel);
		var range = this.preRange;
		range.setStart(this.text_content.body, 0);
		range.setEnd(this.text_content.body, 0);
		var value = range.createContextualFragment("<img src=\"" + src + "\" />");
		var img = value.childNodes[0];
		if(this.startNode == this.endNode) {
			range.setStartAfter(this.startNode);
		} else {
			range.setStartBefore(this.startNode);
		}
		range.setEndAfter(this.endNode);
		//range.setStart(this.startNode, this.startOffset);
		//range.setEnd(this.endNode, this.endOffset);
		if(this.startNode.tagName == "BR") {
			this.startNode.parentNode.insertBefore(img, this.startNode);
		} else {
			if(this.startNode.tagName == "BODY" && this.endNode.tagName == "BODY" ) {
				this.startNode.appendChild(img);
			} else {
				range.insertNode(value);
			}
		}
		return img;
	},
	insertLink: function(params) {
		this.closePopup("createlink");
		
		//親選択
		if(this.preRange.select)
			this.preRange.select();
		if (!params)
			return false;
		if(this.el && this.el.tagName.toLowerCase() == 'a')
			var a = this.el;
		else
			var a = "";
		
		if (!a) try {
			this.text_content.execCommand("createlink", false, params.f_href);
			a = this.getParentElement();
			var sel = this.getSelection();
			var range = this.createRange(sel);
			if (!(browser.isIE || browser.isOpera)) {
				a = range.startContainer;
				if (!/^a$/i.test(a.tagName)) {
					a = a.nextSibling;
					if (a == null)
						a = range.startContainer.parentNode;
				}
			}
		} catch(e) {}
		else {
			var href = params.f_href.trim();
			this.selectNodeContents(a);
			if (href == "") {
				this.text_content.execCommand("unlink", false, null);
				this.updateToolbar();
				return false;
			}
			else {
				a.href = href;
			}
		}
		if (!(a && /^a$/i.test(a.tagName))){
			//新規挿入
			if(params.f_title.strip() != "") var title = params.f_title.strip();
			else var title = params.f_href;		
			if (browser.isIE) {
				var text = "<a href=\"" + params.f_href + "\" ";
				if(params.f_target.strip() != "") {
					text += "target=\""+ params.f_target.strip() + "\" ";
				}
				if(params.f_title.strip() != "") {
					text += "title=\""+ params.f_title.strip() + "\" ";
				}
				text += "/>" + title + "</a>";
				range.pasteHTML(text);
				this.borderChange();
				return;
			} else if(browser.isOpera) {
				//現状、rangeの場所に追加できない
				if (typeof compTextareaLang == "undefined" || typeof compTextareaLang.msg["selectlink_error"] == "undefined") 
					alert("You need to select some text before creating a link");
				else
					alert(compTextareaLang.msg["selectlink_error"]);
				return;
				////var parent_el = a;
				////var a = document.createElement("A");
				////a.href = title;
				////parent_el.parentNode.insertBefore(a, parent_el);
				////range.moveToElementText(a);
				////a.innerHTML = title;
			} else {
				if(browser.isSafari) {
					range.setStart(this.text_content.body, 0);
					range.setEnd(this.text_content.body, 0);
				}
				var value = range.createContextualFragment("<a href=\"" + params.f_href + "\" />" + title + "</a>");
				var a = value.childNodes[0];
				if(browser.isSafari) {
					if(this.startNode == this.endNode) {
						range.setStartAfter(this.startNode);
					} else {
						range.setStartBefore(this.startNode);
					}
					range.setEndAfter(this.endNode);
					//range.setStart(this.startNode, this.startOffset);
					//range.setEnd(this.endNode, this.endOffset);
					if(this.startNode.tagName == "BR") {
						this.startNode.parentNode.insertBefore(a, this.startNode);
					} else {
						range.insertNode(value);
					}
				} else {
						range.insertNode(value);
				}
			}
		}
		a.target = params.f_target.strip();
		a.title = params.f_title.strip();
		this.selectNodeContents(a);
		this.updateToolbar();
		this.borderChange();
	},
	//テーブルマージ処理 OKクリック
	updateTableMerge: function(numCols, numRows) {
		if(numCols > 0 || numRows > 0) {
			var table = null;
			var edit_td = null;
			var rows = new Array();
			
			for (var i = 0, el_array_len = this.el_array.length; i < el_array_len; ++i) {
				var el_tmp = this.el_array[i];
				if (el_tmp.tagName.toLowerCase() == "table") {
					table = el_tmp;
					break;
				}else if (el_tmp.tagName.toLowerCase() == "td") {
					edit_td = el_tmp;
				}
			}
			if(table == undefined)
				return;
			var tableData = this.getTableData(table);
			var cpos = this.getCellPos(tableData, edit_td);
			//var tRows = table.rows;
	
			for (var i=cpos.rowindex,tableData_len = tableData.length; i < tableData_len; i++) {
				var rowCells = new Array();
	
				for (var j= cpos.cellindex, tableData_rowlen = tableData[i].length; j < tableData_rowlen; j++) {
					var td = tableData[i][j];
	
					if (td && !this.inArray(rows, td) && !this.inArray(rowCells, td)) {
						var cp = this.getCellPos(tableData, td);
						if (cp.cellindex >= cpos.cellindex && cp.cellindex < cpos.cellindex+parseInt(numCols) + 1 && 
							cp.rowindex >= cpos.rowindex && cp.rowindex < cpos.rowindex+parseInt(numRows) + 1){
							rowCells[rowCells.length] = td;
						}
					}
				}
	
				if (rowCells.length > 0){
					rows[rows.length] = rowCells;
				}
			}
			// Validate selection and get total rowspan and colspan
			var rowSpan = 1, colSpan = 1;
	
			// Validate horizontal and get total colspan
			var lastRowSpan = -1;
			var row_len = rows.length;
			if(row_len > 0) {
				for (var i=0; i<row_len; i++) {
					var rowColSpan = 0;
		
					for (var j=0; j<rows[i].length; j++) {
						rowColSpan += rows[i][j].colSpan;
		
						if (lastRowSpan != -1 && rows[i][j].rowSpan != lastRowSpan) {
							alert(compTextareaLang.msg["tablemerge_row_error"]);
							return true;
						}
		
						lastRowSpan = rows[i][j].rowSpan;
					}
		
					if (rowColSpan > colSpan)
						colSpan = rowColSpan;
		
					lastRowSpan = -1;
				}
				
				// Validate vertical and get total rowspan
				var lastColSpan = -1;
				for (var i=0; i<rows[0].length; i++) {
					var colRowSpan = 0;
					
					for (var j=0, col_len = rows.length; j<col_len; j++) {
						colRowSpan += rows[j][i].rowSpan;
						if (lastColSpan != -1 && rows[j][i].colSpan != lastColSpan) {
							alert(compTextareaLang.msg["tablemerge_col_error"]);
							return true;
						}
		
						lastColSpan = rows[j][i].colSpan;
					}
		
					if (colRowSpan > rowSpan)
						rowSpan = colRowSpan;
		
					lastColSpan = -1;
				}
		
				// Setup td
				tdElm = rows[0][0];
				tdElm.rowSpan = rowSpan;
				tdElm.colSpan = colSpan;
		
				// Merge cells
				for (var i=0; i<rows.length; i++) {
					for (var j=0; j<rows[i].length; j++) {
						var html = rows[i][j].innerHTML;
						if(html == "<br>" || html == "<br />" || html == "&nbsp;") {
							//BRタグのみ
							;
						} else {
							tdElm.innerHTML += html;
						}
						// Not current cell
						if (rows[i][j] != tdElm && !rows[i][j]._deleted) {
							var cpos = this.getCellPos(tableData, rows[i][j]);
							var tr = rows[i][j].parentNode;
		
							tr.removeChild(rows[i][j]);
							rows[i][j]._deleted = true;
		
							// Empty TR, remove it
							if (!tr.hasChildNodes()) {
								tr.parentNode.removeChild(tr);
		
								var lastCell = null;
								for (var x=0; cellElm = tableData[cpos.rowindex][j]; j++) {
									if (cellElm != lastCell && cellElm.rowSpan > 1)
										cellElm.rowSpan--;
		
									lastCell = cellElm;
								}
		
								if (tdElm.rowSpan > 1)
									tdElm.rowSpan--;
							}
						}
					}
					if(browser.isGecko && tdElm.innerHTML == "")
						tdElm.innerHTML = "&nbsp;";
				}
			}
		}
		this.closePopup("tablemerge");
	},
	closePopup: function(cmdID) {
		if(this.popup[this.popupPrefix + this.id + cmdID]) {
			this.popup[this.popupPrefix + this.id + cmdID].closePopup();
			if(cmdID == "inserttable" && this.popup[this.popupPrefix + this.id + "edittable"]) {
				this.closePopup("edittable");
			}
		}
	},
	//テーブルプロパティOKクリック
	updateTable: function(edit_name, update_area) {
		//繰り返し更新(再帰処理)
		if(update_area != undefined && update_area > 0) {
			for (var i = 0; i < this.el_array.length; ++i) {
				var el_tmp = this.el_array[i];
				if (el_tmp.tagName.toLowerCase() == "table" && (edit_name == "edittablerow" || (edit_name == "edittablecell" && update_area==2))) {
					break;
				}else if (el_tmp.tagName.toLowerCase() == "tr" && edit_name == "edittablecell" && update_area==1) {
					break;
				}
			}
			if(edit_name == "edittablerow"){
				//tr検索
				var trList = el_tmp.getElementsByTagName("tr");
				for (var i = 0; i < trList.length; i++){
					this.el = trList[i];
					this.updateTable(edit_name,-1);
				}
				
			}else{
				//td検索
				var tdList = el_tmp.getElementsByTagName("td");
				for (var i = 0; i < tdList.length; i++){
					this.el = tdList[i];
					this.updateTable(edit_name,-1);
				}
			}
			//ダイアログを閉じる
			this.closePopup(edit_name);
			return ;
		}
		
		//テーブルプロパティダイアログ検索
		var el = $(this.popup[this.popupPrefix + this.id + edit_name].popupID);
		
		if(el == undefined)
			return;
		//プロパティセット
		if(el != undefined ) {
			ret = this.setDialogProperty(el);
			if(!ret)
				return false;
		}
		//ダイアログを閉じる
		if(update_area == undefined || update_area >= 0)
			this.closePopup(edit_name);
		//テーブルアップデート
		var el_style = this.el.style;
		for (var field in this.tableProperty) {
			var value = this.tableProperty[field];
			//if (!value) {
			//	continue;
			//}
			if (edit_name == "edittable" && field.substr(0,1)!='f') 
				continue;
			else if(edit_name == "edittablerow" && field.substr(0,1)!='r') 
				continue;
			else if(edit_name == "edittablecell" && field.substr(0,1)!='c') 
				continue;
			
			switch (field) {
			    case "f_width"   :
					if(value=="")
						this.tableProperty.f_w_unit = "";

					el_style.width = value + this.tableProperty.f_w_unit; break;
					break;
				case "r_width"   :
					if(value=="")
						this.tableProperty.r_w_unit = "";

					el_style.width = value + this.tableProperty.r_w_unit; break;
					break;
				case "c_width"   :
					if(value=="")
						this.tableProperty.c_w_unit = "";

					el_style.width = value + this.tableProperty.c_w_unit; break;
					break;
				case "f_height"  : 
					if(value=="")
						this.tableProperty.f_h_unit = "";
					el_style.height = value + this.tableProperty.f_h_unit; break;
					break;
				case "r_height"  : 
					if(value=="")
						this.tableProperty.r_h_unit = "";
					el_style.height = value + this.tableProperty.r_h_unit; break;
					break;
				case "c_height"  : 
					if(value=="")
						this.tableProperty.c_h_unit = "";
					el_style.height = value + this.tableProperty.c_h_unit; break;
					break;
			    case "f_align"   : this.el.align = value; break;
				case "r_align"   : 
				case "c_align"   : 
					el_style.textAlign = value; 
					break;
				case "r_valign"   : 
				case "c_valign"   : 
					el_style.verticalAlign = value; break;
			    case "f_border"  : 
					this.el.border = parseInt(value); 
					if(parseInt(value) == 0)
						el_style.border = "1px dotted #666666";
					else if(this.tableProperty.f_border_style !="" || this.tableProperty.f_border_color !=""){
						el_style.borderWidth = parseInt(value)+"px";
						el_style.borderColor = this.tableProperty.f_border_color;
						el_style.borderStyle = this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style;
					}
					break;
				case "c_t_border"  :
					var parent_el = Element.getParentElement(this.el,3);
					if(parent_el.tagName.toLowerCase() == "table" && parent_el.border == 0)
						el_style.borderTop = "1px dotted #666666";
					else if(this.tableProperty.c_t_border_style !="" || this.tableProperty.c_t_border_color !=""){
						el_style.borderTopWidth = parseInt(value)+"px";
						el_style.borderTopColor = this.tableProperty.c_t_border_color;
						el_style.borderTopStyle = this.tableProperty.c_t_border_style;
					}
					break;
				case "c_r_border"  :
					var parent_el = Element.getParentElement(this.el,3);
					if(parent_el.tagName.toLowerCase() == "table" && parent_el.border == 0)
						el_style.borderRight = "1px dotted #666666";
					else if(this.tableProperty.c_r_border_style !="" || this.tableProperty.c_r_border_color !=""){
						el_style.borderRightWidth = parseInt(value)+"px";
						el_style.borderRightColor = this.tableProperty.c_r_border_color;
						el_style.borderRightStyle = this.tableProperty.c_r_border_style;
					}
					break;
				case "c_b_border"  :
					var parent_el = Element.getParentElement(this.el,3);
					if(parent_el.tagName.toLowerCase() == "table" && parent_el.border == 0)
						el_style.borderBottom = "1px dotted #666666";
					else if(this.tableProperty.c_b_border_style !="" || this.tableProperty.c_b_border_color !=""){
						el_style.borderBottomWidth = parseInt(value)+"px";
						el_style.borderBottomColor = this.tableProperty.c_b_border_color;
						el_style.borderBottomStyle = this.tableProperty.c_b_border_style;
					}
					break;
				case "c_l_border"  :
					var parent_el = Element.getParentElement(this.el,3);
					if(parent_el.tagName.toLowerCase() == "table" && parent_el.border == 0)
						el_style.borderLeft = "1px dotted #666666";
					else if(this.tableProperty.c_l_border_style !="" || this.tableProperty.c_l_border_color !=""){
						el_style.borderLeftWidth = parseInt(value)+"px";
						el_style.borderLeftColor = this.tableProperty.c_l_border_color;
						el_style.borderLeftStyle = this.tableProperty.c_l_border_style;
					}
					break;
			    case "f_spacing" : this.el.cellSpacing = parseInt(value); break;
			    case "f_padding" : this.el.cellPadding = parseInt(value); break;
				case "f_background" : 
				case "r_background" : 
				case "c_background" : 
					if(value!="")
						el_style.backgroundColor=value;
					else
						el_style.backgroundColor="";
					break;
				case "r_fontcolor" : 
				case "c_fontcolor" : 
					if(value!="")
						el_style.color=value;
					else
						el_style.color="";
					break;
				case "f_collapse" :
					if(value)
						el_style.borderCollapse = "collapse";
					else
						el_style.borderCollapse = "";
					break;
				case "c_nowrap" :
					if(value)
						el_style.whiteSpace = "nowrap";
					else
						el_style.whiteSpace = "";	//"normal";
					break;
				case "f_horiz" :
					if(value) {
						el_style.marginLeft = parseInt(value) + "px";
						el_style.marginRight = parseInt(value) + "px";
					}
					break;
				case "f_vert" :
					if(value) {
						el_style.marginTop = parseInt(value) + "px";
						el_style.marginBottom = parseInt(value) + "px";
					}
					break;
			}
		}
		if(this.el.tagName.toLowerCase() == "table") {
			var tdList = this.el.getElementsByTagName("td");
			var col = 0;
			for (var i = 0; i < tdList.length; i++){
				col = col + tdList[i].colSpan;
			}
			col = col/this.el.rows.length;

			var cellwidth = 0;
			if (this.tableProperty.f_fixed)
				cellwidth = Math.floor(100 / parseInt(col));
			var td = null;
			for (var i = 0; i < tdList.length; i++){
				var td_style = tdList[i].style;
				if(this.tableProperty.f_border == 0)
					td_style.border = "1px dotted #666666";
				else if(this.tableProperty.f_border_style !="" || this.tableProperty.f_border_color !=""){
					td_style.borderWidth = parseInt(this.tableProperty.f_border)+"px";
					td_style.borderColor = this.tableProperty.f_border_color;
					//td_style.borderStyle = this.tableProperty.f_border_style;
					td_style.borderStyle = this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style + " " + this.tableProperty.f_border_style;
					//el_style.border	 = parseInt(this.tableProperty.f_border)+"px"+ this.tableProperty.f_border_style + this.tableProperty.f_border_color;
				}
				var re = /\s*%/;	
				if (cellwidth!=0)
					td_style.width = cellwidth*tdList[i].colSpan + "%";
				else if (td_style.width.match(re)) 
					td_style.width = "";
			}
			var table = this.el;
		} else {
			var table = this.el;
			while(1) {
				table = table.parentNode;
				if(!table) {
					break;
				}
				if(table.tagName.toLowerCase() == "table") {
					break;
				}
			}
		}
		//表の再描画処理 FireFox 反映されないため
		if(table) {
			this.tableRedraw(table);
		}
		this.forceRedraw();
		this.focusEditor();
	},
	getTableData: function(table) {
		var rows = table.rows;
		var ret = new Array();
		
		for (var i=0; i<rows.length; i++) {
			for (var j=0; j<rows[i].cells.length; j++) {
				var td = rows[i].cells[j];

				// All ready filled
				for (jstart = j; ret[i] && ret[i][jstart]; jstart++) ;

				// Fill box
				for (var i2=i; i2<i+td.rowSpan; i2++) {
					if (!ret[i2])
						ret[i2] = new Array();

					for (var j2=jstart; j2 < jstart+td.colSpan; j2++) {
						ret[i2][j2] = td;
					}
				}
			}
		}
		return ret;
	},
	inArray: function(ar, v) {
		for (var i=0; i<ar.length; i++) {
			// 配列かどうか
			if (ar[i].length > 0 && this.inArray(ar[i], v))
				return true;

			if (ar[i] == v)
				return true;
		}

		return false;
	},
	getCellPos: function(tableData, td) {
		for (var y=0; y<tableData.length; y++) {
			for (var x=0; x<tableData[y].length; x++) {
				if (tableData[y][x] == td)
					return {cellindex : x, rowindex : y};
			}
		}

		return null;
	},
	showDialogBox: function(cmdID, action_name, el, right_flag , offset, modal_flag) {
		var update_flag = this.update_flag;
		//IMG取得
		var EX1 = Position.cumulativeOffset(el)[0];
		var EY1 = Position.cumulativeOffset(el)[1];
		var EY2 = el.offsetHeight + EY1;
		var EX2 = el.offsetWidth + EX1;	
		offset = (offset == undefined || offset == null) ? [0,0] : offset;
		modal_flag = (modal_flag == undefined || modal_flag == null) ? true : modal_flag; 
		if(right_flag) {
			var x = EX2 + offset[0];
			var y = EY1 + offset[1];
		} else {
			var x = EX1 + offset[0];
			var y = EY2 + offset[1];
		}
		
		if(browser.isSafari) {
			var sel = this.preSel;
			if(sel.focusNode) {
				// Setup before range
				var rngBefore = this.createRange(sel);
				//rngBefore.setStart(sel.anchorNode, sel.anchorOffset);
				rngBefore.setEndBefore(sel.anchorNode);
				rngBefore.collapse(true);
	
				// Setup after range
				var rngAfter = this.createRange(sel);
				//rngAfter.setStart(sel.focusNode, sel.focusOffset);
				rngAfter.setEndAfter(sel.focusNode);
				rngAfter.collapse(true);
			
				var direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;
				this.startNode = direct ? sel.anchorNode : sel.focusNode;
				this.startOffset = direct ? sel.anchorOffset : sel.focusOffset;
				this.endNode = direct ? sel.focusNode : sel.anchorNode;
				this.endOffset = direct ? sel.focusOffset : sel.anchorOffset;
			} else {
				this.startNode = this.text_content.body;
				this.endNode = this.text_content.body;
				this.startOffset = 0;
				this.endOffset = 0;
			}
		} else {
			var sel = this.getSelection();
			this.preRange = this.createRange(sel);
		}
		//if((cmdID == "insertimage" || cmdID == "insertupload") && !browser.isIE) {
			//Safariの場合、srcからiframeを表示しなければ、リファラが取得できないため
			var src = _js_url + "/include/comp/textarea/popup.php" + "?prefix_id_name="+ "dialog_"+cmdID + "&parent_name=" + 
						this.id + this.popupPrefix + "&cmd_name=" + cmdID + "&update_flag=" + update_flag;
			/*
			var queryParams = commonCls.getParams(this.id);
			if(queryParams) {
				var page_id = queryParams["page_id"];
				var block_id = queryParams["block_id"];
				var module_id = queryParams["module_id"];
				if(page_id) src += "&page_id=" + page_id;
				if(block_id) src += "&block_id=" + block_id;
				if(module_id) src += "&module_id=" + module_id;
			}
			*/
			this._showPopup(cmdID, null, x, y, modal_flag, src);
		/*
		} else {
			var dialog_params = new Object();
			dialog_params["param"] = {"action":action_name,"prefix_id_name":"dialog_"+cmdID, "parent_id":this.id, "cmd_name":cmdID, "update_flag":update_flag};
			//dialog_params["loading_el"] = el;
			dialog_params["top_el"] = this.id;
			dialog_params["script_flag"] = false;		//scriptを実行しない
			dialog_params["callbackfunc"] = function(res) {
				if(!modal_flag && cmdID == "edittable") {
					var insert_el = $(this.popup[this.popupPrefix + this.id + "inserttable"].popupID);
					if(!insert_el || insert_el.style.display == "none") {
						return;
					}
				}
				this._showPopup(cmdID, res, x, y, modal_flag);
			}.bind(this);
			commonCls.send(dialog_params);
		}
		*/
	},
	_showPopup: function(cmdID, res, x, y, modal_flag, src) { 
		//commonCls.moduleInit切り出し
		//var re_modinit = new RegExp("commonCls.moduleInit.*;", "i");
		//res = res.replace(re_modinit, "");
		if(!this.popup[this.popupPrefix + this.id + cmdID]) {
			this.popup[this.popupPrefix + this.id + cmdID] = new compPopup(document.body, this.popupPrefix + this.id + cmdID);
		}
		if(modal_flag) {
			this.popup[this.popupPrefix + this.id + cmdID].observer = function(){this.closePopup(cmdID);}.bind(this);
			this.popup[this.popupPrefix + this.id + cmdID].observing = true;
			this.popup[this.popupPrefix + this.id + cmdID].modal = true;
		} else {
			//this.popup[this.popupPrefix + this.id + cmdID].observer = function(){this.closePopup(cmdID);}.bind(this);
			this.popup[this.popupPrefix + this.id + cmdID].observing = false;
			this.popup[this.popupPrefix + this.id + cmdID].modal = false;
		}
		if(typeof compTextareaLang != "undefined" && typeof compTextareaLang.icons[cmdID] != "undefined") {
			this.popup[this.popupPrefix + this.id + cmdID].setTitle(compTextareaLang.icons[cmdID]);
		}
		this.popup[this.popupPrefix + this.id + cmdID].setPosition(Array(x, y));
		if(res == null) {
			this.popup[this.popupPrefix + this.id + cmdID].showSrcPopup(src);
		} else {
			this.popup[this.popupPrefix + this.id + cmdID].showPopup(res);
		}
		
	},
	setDialogProperty: function(el) {
		var contentWin = el.contentWindow;
		if(contentWin && contentWin.getProperty != undefined) {
			var params = contentWin.getProperty();
			if(params == false)
				return false;
			for (var field in params) {
				var value = eval("params." + field);
				this.tableProperty[field] = value;
			}
		}
		return true;
	},
	showCellSetProperty: function(el) {
		//tr or tdの値セット
		// assign the given arguments
		if(el) {
			var el_style = el.style;
			for (var field in this.tableProperty) {
				var value = this.tableProperty[field];
				if (el.tagName.toLowerCase() == "tr" && field.substr(0,1)!='r') 
					continue;
				else if(el.tagName.toLowerCase() == "td" && field.substr(0,1)!='c') 
					continue;
								
				switch (field) {
				    case "r_width"   :
						var re = /\s*%/;
						if (el_style.width.match(re)) {
							this.tableProperty.r_w_unit = "%";
						}else{
							this.tableProperty.r_w_unit = "px";
						}
						this.tableProperty.r_width = (isNaN(parseInt(el_style.width))==true) ? "" : parseInt(el_style.width);
						break;
					case "c_width"   :
						var re = /\s*%/;
						if (el_style.width.match(re)) {
							this.tableProperty.c_w_unit = "%";
						}else{
							this.tableProperty.c_w_unit = "px";
						}
						this.tableProperty.c_width = (isNaN(parseInt(el_style.width))==true) ? "" : parseInt(el_style.width);
						break;
					case "r_height"  : 
						var re = /\s*%/;
						if (el_style.height.match(re)) {
							this.tableProperty.r_h_unit = "%";
						}else{
							this.tableProperty.r_h_unit = "px";
						}
						this.tableProperty.r_height = (isNaN(parseInt(el_style.height))==true) ? "" : parseInt(el_style.height);
						break;
					case "c_height"  : 
						var re = /\s*%/;
						if (el_style.height.match(re)) {
							this.tableProperty.c_h_unit = "%";
						}else{
							this.tableProperty.c_h_unit = "px";
						}
						this.tableProperty.c_height = (isNaN(parseInt(el_style.height))==true) ? "" : parseInt(el_style.height);
						break;
				    case "r_align"   : 
						this.tableProperty.r_align = el_style.textAlign; break;
					case "c_align"   : 
						this.tableProperty.c_align = el_style.textAlign; break;
					case "r_valign"   : 
						this.tableProperty.r_valign = el_style.verticalAlign; break;
					case "c_valign"   : 
						this.tableProperty.c_valign = el_style.verticalAlign; break;
				    case "c_t_border"  : 
						this.tableProperty.c_t_border = (isNaN(parseInt(el_style.borderTopWidth))==true) ? "" : parseInt(el_style.borderTopWidth);
						this.tableProperty.c_t_border_style = el_style.borderTopStyle;
						this.tableProperty.c_t_border_color = this.getColorCode(el, "borderTopColor");
						break;
					case "c_r_border"  : 
						this.tableProperty.c_r_border = (isNaN(parseInt(el_style.borderRightWidth))==true) ? "" : parseInt(el_style.borderRightWidth);
						this.tableProperty.c_r_border_style = el_style.borderRightStyle;
						this.tableProperty.c_r_border_color = this.getColorCode(el, "borderRightColor");
						break;
					case "c_b_border"  : 
						this.tableProperty.c_b_border = (isNaN(parseInt(el_style.borderBottomWidth))==true) ? "" : parseInt(el_style.borderBottomWidth);
						this.tableProperty.c_b_border_style = el_style.borderBottomStyle;
						this.tableProperty.c_b_border_color = this.getColorCode(el, "borderBottomColor");
						break;
					case "c_l_border"  : 
						this.tableProperty.c_l_border = (isNaN(parseInt(el_style.borderLeftWidth))==true) ? "" : parseInt(el_style.borderLeftWidth);
						this.tableProperty.c_l_border_style = el_style.borderLeftStyle;
						this.tableProperty.c_l_border_color = this.getColorCode(el, "borderLeftColor");
						break;
				    case "r_background" : 
						this.tableProperty.r_background = this.getColorCode(el, "backgroundColor");
						break;
					case "c_background" : 
						this.tableProperty.c_background = this.getColorCode(el, "backgroundColor");
						break;
					case "r_fontcolor" : 
						this.tableProperty.r_fontcolor = this.getColorCode(el, "color");
						break;
					case "c_fontcolor" : 
						this.tableProperty.c_fontcolor = this.getColorCode(el, "color");
						break;
					case "c_nowrap" :
						this.tableProperty.c_nowrap = el_style.whiteSpace;
						break;
				}
			}
			
		}
		if (el.tagName.toLowerCase() == "tr") {
			var cmdID = "edittablerow";
		} else {
			var cmdID = "edittablecell";
		}
		
		this.el =el;
		this.update_flag = true;		
		var tablemenu_el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_" + "tablemenu");
		this.showDialogBox(cmdID, "comp_textarea_view_" + cmdID, tablemenu_el, true);
		this.closePopup("tablemenu");
	},
	showTableSetProperty: function(el) {
		//tableの値セット
		// assign the given arguments
		var table = el;
		if(table) {
			for (var field in this.tableProperty) {
				var value = this.tableProperty[field];
				switch (field) {
				    case "f_width"   :
						var re = /\s*%/;
						if (table.style.width.match(re)) {
							this.tableProperty.f_w_unit = "%";
						}else{
							this.tableProperty.f_w_unit = "px";
						}
						this.tableProperty.f_width = (isNaN(parseInt(table.style.width))==true) ? "" : parseInt(table.style.width);
						break;
					case "f_height"  : 
						var re = /\s*%/;
						if (table.style.height.match(re)) {
							this.tableProperty.f_h_unit = "%";
						}else{
							this.tableProperty.f_h_unit = "px";
						}
						this.tableProperty.f_height = (isNaN(parseInt(table.style.height))==true) ? "" : parseInt(table.style.height);
						break;
				    case "f_align"   : this.tableProperty.f_align = table.align; break;
				    case "f_border"  : 
						if(table.border == 0) {
							this.tableProperty.f_border = "0";
						}else{
							this.tableProperty.f_border = (isNaN(parseInt(table.style.borderWidth))==true) ? "" : parseInt(table.style.borderWidth);
							this.tableProperty.f_border_style = table.style.borderStyle;
							this.tableProperty.f_border_color = this.getColorCode(table, "borderColor");
						}
						break;
				    case "f_spacing" : this.tableProperty.f_spacing = table.cellSpacing; break;
				    case "f_padding" : this.tableProperty.f_padding = table.cellPadding; break;
					case "f_background" : 
						this.tableProperty.f_background = this.getColorCode(table, "backgroundColor");
						break;
					case "f_collapse" :
						this.tableProperty.f_collapse = table.style.borderCollapse;
						break;
					case "f_horiz" :
						this.tableProperty.f_horiz = valueParseInt(table.style.marginLeft);
						break;
					case "f_vert" :
						this.tableProperty.f_vert = valueParseInt(table.style.marginTop);
						break;
				}
			}
			var tdList = table.getElementsByTagName("td");
			var col = 0;
			for (var i = 0; i < tdList.length; i++){
				col = col + tdList[i].colSpan;
			}
			col = col/table.rows.length;

			var cellwidth = 0;
			cellwidth = Math.floor(100 / parseInt(col));
			var td_tmp = null;
			var fix_flag = true;
			for (var i = 0; i < tdList.length; i++){
				td_tmp = tdList[i];
				
				if (cellwidth*tdList[i].colSpan + "%"==td_tmp.style.width)
					;
				else{
					fix_flag = false;
					break;
				}
			}
			if(fix_flag)
				this.tableProperty.f_fixed = true;
			else
				this.tableProperty.f_fixed = false;
		}
		var update_flag = false;
		if(typeof el != "undefined") {
			this.el = el;
			update_flag = true;
		}
		this.update_flag = update_flag;
		//var tablemenu_el = $(this.popup[this.popupPrefix + this.id + "tablemenu"].popupID);
		if(this.popup[this.popupPrefix + this.id + "edittable"] && this.popup[this.popupPrefix + this.id + "edittable"].isVisible()) {
			this.closePopup("edittable");
		} else {
			if(table) {
				var tablemenu_el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_" + "tablemenu");
				this.showDialogBox("edittable", "comp_textarea_view_edittable", tablemenu_el, true);
				this.closePopup("tablemenu");
			} else {
				var inserttable_el = $(this.popup[this.popupPrefix + this.id + "inserttable"].popupID);
				//modalにしない
				this.showDialogBox("edittable", "comp_textarea_view_edittable", inserttable_el, true, null, false);
			}
		}
	},
	isBlockElement: function(el) {
		var blockTags = " body form textarea fieldset ul ol dl li div " +
"p h1 h2 h3 h4 h5 h6 quote pre table thead " +
"tbody tfoot tr td iframe address ";
		return el && el.nodeType == 1 && (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
	},
	// Returns an array with all the ancestor nodes of the selection.
	getAllAncestors: function() {
		var p = this.getParentElement();
		var a = [];
		while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
			a.push(p);
			p = p.parentNode;
		}
		a.push(this.text_content.body);
		return a;
	},
	getParentElementByTagName : function(n, na, f, r) {
		var re = na ? new RegExp('^(' + na.toUpperCase().replace(/,/g, '|') + ')$') : 0, v;

		// Compatiblity with old scripts where f param was a attribute string
		if (f && typeof(f) == 'string')
			return this.getParentElementByTagName(n, na, function(no) {return this.getAttrib(no, f) !== '';}.bind(this));

		return this.getParentNode(n, function(n) {
			return ((n.nodeType == 1 && !re) || (re && re.test(n.nodeName))) && (!f || f(n));
		}, r);
	},

	getParentNode : function(n, f, r) {
		while (n) {
			if (n == r)
				return null;

			if (f(n))
				return n;

			n = n.parentNode;
		}

		return null;
	},
	
	getAttrib : function(elm, name, dv) {
		var v;
		if (typeof(dv) == "undefined")
			dv = "";

		// Not a element
		if (!elm || elm.nodeType != 1)
			return dv;

		try {
			v = elm.getAttribute(name, 0);
		} catch (e) {
			// IE 7 may cast exception on invalid attributes
			v = elm.getAttribute(name, 2);
		}

		// Try className for class attrib
		if (name == "class" && !v)
			v = elm.className;

		// Workaround for a issue with Firefox 1.5rc2+
		if (browser.isGecko) {
			if (name == "src" && elm.src != null && elm.src !== '')
				v = elm.src;

			// Workaround for a issue with Firefox 1.5rc2+
			if (name == "href" && elm.href != null && elm.href !== '')
				v = elm.href;
		} else if (browser.isIE) {
			switch (name) {
				case "http-equiv":
					v = elm.httpEquiv;
					break;

				case "width":
				case "height":
					v = elm.getAttribute(name, 2);
					break;
			}
		}

		if (name == "style" && !browser.isOpera)
			v = elm.style.cssText;

		return (v && v !== '') ? v : dv;
	},
	
	// Returns the deepest node that contains both endpoints of the selection.
	getParentElement: function() {
		var sel = this.getSelection();
		var range = this.createRange(sel);
		if ((browser.isIE || browser.isOpera)) {
			switch (sel.type) {
			    case "Text":
			    case "None":
				// It seems that even for selection of type "None",
				// there _is_ a parent element and it's value is not
				// only correct, but very important to us.  MSIE is
				// certainly the buggiest browser in the world and I
				// wonder, God, how can Earth stand it?
				return range.parentElement();
			    case "Control":
				return range.item(0);
			    default:
				return this.text_content.body;
			}
		} else if(browser.isSafari) {
			if(sel.focusNode) {
				return sel.anchorNode;
				// sel.focusNode
			} else {
				return null;
			}
		} else try {
			var p = range.commonAncestorContainer;
			if (!range.collapsed && range.startContainer == range.endContainer &&
			    range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes())
				p = range.startContainer.childNodes[range.startOffset];
			/*
			alert(range.startContainer + ":" + range.startOffset + "\n" +
			      range.endContainer + ":" + range.endOffset);
			*/
			while (p.nodeType == 3) {
				p = p.parentNode;
			}
			return p;
		} catch (e) {
			return null;
		}
	},
	getSelectElements: function() {
		var sel = this.getSelection();
		var range = this.createRange(sel);
		var ret_el = Array();
		if ((browser.isIE || browser.isOpera)) {
			switch (sel.type) {
			    case "Text":
			    case "None":
			    	// It seems that even for selection of type "None",
					// there _is_ a parent element and it's value is not
					// only correct, but very important to us.  MSIE is
					// certainly the buggiest browser in the world and I
					// wonder, God, how can Earth stand it?
					
					var bufText = range.htmlText.replace(/[\n\r]/g,"");
					var el = range.parentElement();
					if(el.tagName == "BODY") {
						var j = 0;
						for (var i = 0; i < el.childNodes.length; i++) {
							var re_el = new RegExp(el.childNodes[i].outerHTML.replace(/[\n\r]/g,""), "i");
							//中身が同一なものが含まれていた場合、
							//正確にエレメントを取得できない
							if(this.isBlockElement(el.childNodes[i]) && bufText.match(re_el)) {
								ret_el[j] = el.childNodes[i];
								j++;
							}
						}
					} else {
						var re_el = new RegExp(el.outerHTML.replace(/[\n\r]/g,""), "i");
						bufText = bufText.replace(re_el, "");
						ret_el[0] = el;
						if(bufText.length > 0) {
							var j = 1;
							while(1) {
								el = el.previousSibling;
								if(!el) {
									break;
								}
								var re_pre_el = new RegExp(el.outerHTML.replace(/[\n\r]/g,""), "i");
								if(this.isBlockElement(el) && bufText.match(re_pre_el)) {
									bufText = bufText.replace(re_pre_el, "");
									ret_el[j] = el;
									j++;
								}
							}
						}
					}
					break;
			    case "Control":
				    for (var i = 0; i < range.length; i++) {
				    	ret_el[i] = range.item(i);
				    }
				    break;
			    default:
			    	ret_el[0] = this.text_content.body
			}
			return ret_el;
		} else try {
			var el = range.startContainer.parentNode;
			var end_el = range.endContainer.parentNode;
			if(el == end_el) {
				ret_el[0] = el;
			} else {
				var i = 0;
				while(el) {
					if(this.isBlockElement(el)) {ret_el[i] = el;i++;}
					if(el == end_el) {
						break;
					}
					el = el.nextSibling;
				}
			}
			return ret_el;
		} catch (e) {
			return null;
		}
	},
	// el is reference to the SELECT object
	// txt is the name of the select field, as in config.toolbar
	comboSelected: function(el, txt) {
		this.focusEditor();
		var value = el.options[el.selectedIndex].value;
		switch (txt) {
		    case "fontsize": 
		    	if(!browser.isSafari) {
		    		this.execCommand(txt, false, value); 
		    	} else {
		    		var fontsize = ["8","10","12","14","18","24","36"];
		    		this.sizeElement.style.fontSize = fontsize[value]+"px";
		    	}
		    	break;
		    case "fontname": 
		 	    if(browser.isNS) {
		    		//日本語フォントの場合、文字化けするため修正
		    		this.execCommand("formatblock", false, "span");
		    		var el = this.getParentElement();
		    		Element.setStyle(el,{"font-family":value});
		    	} else {
		    		this.execCommand(txt, false, value);
		    	}
		    	break;
		    case "formatblock":
			((browser.isIE || browser.isOpera)) && (value = "<" + value + ">");
			if (browser.isIE && new RegExp('blockquote|code|samp', 'gi').test(value)) {
				this.execCommand(txt, false, '<p>');
				var el = this.getParentElement();
				var new_el = this.text_content.createElement(value);
				if(value == "blockquote") Element.addClassName(new_el, "quote");	//固定
				ar = el.attributes;
				for (i=ar.length-1; i>-1; i--) {
					if (ar[i].specified && ar[i].nodeValue)
						new_el.setAttribute(ar[i].nodeName.toLowerCase(), ar[i].nodeValue);
				}
				ar = el.childNodes;
				for (i=0; i<ar.length; i++)
					new_el.appendChild(ar[i].cloneNode(true));
				el.parentNode.replaceChild(new_el, el);
				
			} else {
				this.execCommand(txt, false, value);
			}
			break;
		    default:
			// try to look it up in the registered dropdowns
			var dropdown = this.config.customSelects[txt];
			if (typeof dropdown != "undefined") {
				dropdown.action(this);
			} else {
				alert("FIXME: combo box " + txt + " not implemented");
			}
		}
	},
	execCommand: function(cmdID, UI, param) {
		var el = Element.getChildElementByClassName(this.htmlarea, "comptextarea_"+cmdID);	
		if(cmdID != "addundolevel" && cmdID != "foce_addundolevel") {
			this.focusEditor();
		}
		var text_content = this.text_content;
		//TODO:textfocus 後に修正?
		cmdID = cmdID.toLowerCase();
		switch (cmdID) {
			case "undo":
			case "redo":
				if (this.custom_undo_redo){
					this[cmdID].bind(this)();
				}else
					this.text_content.execCommand(cmdID, UI, param);
				if(browser.isIE || browser.isOpera){
					this.forceRedraw();
					this.toolbar.focus();
				}
				break;
			case "cut":
		    case "copy":
		    case "paste":
				try {
					this.text_content.execCommand(cmdID, UI, param);
					//if (this.config.killWordOnPaste)
					//	this.wordClean();
				} catch (e) {
					if (browser.isGecko) {
						if (typeof TextArea.LangSet.msg["Moz-Clipboard"] == "undefined") {
							TextArea.LangSet.msg["Moz-Clipboard"] =
								"Unprivileged scripts cannot access Cut/Copy/Paste programatically " +
								"for security reasons.  Click OK to see a technical note at mozilla.org " +
								"which shows you how to allow a script to access the clipboard.\n\n" +
								"[FIXME: please translate this message in your language definition file.]";
						}
						if (confirm(TextArea.LangSet.msg["Moz-Clipboard"]))
							window.open("http://mozilla.org/editor/midasdemo/securityprefs.html");
					}
				}
				break;
			case "lefttoright":
		    case "righttoleft":
				var dir = (cmdID == "righttoleft") ? "rtl" : "ltr";
				var el = this.getParentElement();
				while (el && !this.isBlockElement(el)){
					el = el.parentNode;
				}
				if (el) {
					if (el.style.direction == dir)
						el.style.direction = "";
					else
						el.style.direction = dir;
				}
				break;
			case "sethilitecolor":
				cmdID = "hilitecolor";
				(browser.isIE || browser.isOpera || browser.isSafari) && (cmdID = "backcolor");
				text_content.execCommand(cmdID, false, this.getColorCode(el, "backgroundColor"));
				break;
			case "setforecolor":
				cmdID = "forecolor";
				text_content.execCommand("forecolor", false, this.getColorCode(el, "backgroundColor"));
				break;
			case "hilitecolor":
				//(browser.isIE || browser.isOpera) && (cmdID = "backcolor");
	    	case "forecolor":
				this.showColorDialog(cmdID, el);
				break;
			case "inserttable": this.showTableDialog(el); break;
			case "tablemenu":	this.showTableMenuDialog(el); break;
			case "createlink":	this.createLinkDialog(); break;
			case "insertimage":	this.insertImageDialog(); break;
			case "inserttex":	this.insertTexDialog(); break;
			case "insertupload":	this.insertUploadDialog(); break;
			case "insertsmiley":this.insertSmileyDialog(el); break;
			case "savezip":this.saveZip(); break;
			case "foce_addundolevel":
			case "addundolevel":
				++this.custom_undo_redo_levels;
				if (this.custom_undo_redo_levels >= this.custom_undo_redo_maxlevels) {
					// remove the first element
					this.undoLevels.shift();
					--this.custom_undo_redo_levels;
				}
				// use the fasted method (getInnerHTML);
				var take = true;

				var text = this.text_content.body.innerHTML;

				if (this.custom_undo_redo_levels > 0)
					take = (this.undoLevels[this.custom_undo_redo_levels - 1] != text);
				if (cmdID == "foce_addundolevel" || take) {
					this.undoLevels[this.custom_undo_redo_levels] = text;
				} else {
					this.custom_undo_redo_levels--;
				}
				break;
			case "indent":
			case "outdent":
				if ((browser.isIE )) {
					var margin_px = (cmdID == "indent") ? 20 : -20;
					var value = (browser.isIE || browser.isOpera) ? "<div>" : "div";
					this.text_content.execCommand("formatblock", false, value);
					var el_arr = this.getSelectElements();
					for (var i = 0; i < el_arr.length; i++) {
						this.indentDiv(el_arr[i], margin_px);
					}
				} else {
					this.text_content.execCommand(cmdID, UI, param);
				}
				break;
			case "unlink":
				// Unlink if caret is inside link
				if (!browser.isOpera) {
					var el = this.getParentElement();
					if(el) {
						var anchorLink = this.getParentElementByTagName(el, "a", "href");
						if(anchorLink) {
							if (browser.isSafari) {
								var sel = this.getSelection();
								var range = this.createRange(sel);
								range.setStart(this.text_content.body, 0);
								range.setEnd(this.text_content.body, 0);
								var value = range.createContextualFragment(anchorLink.innerHTML);
								range.selectNode(anchorLink);
								range.deleteContents();
								range.insertNode(value);
								return;
							}
							this.selectNodeContents(anchorLink);
						}
					}
				}
				this.text_content.execCommand(cmdID, UI, param);
				break;
			case "strikethrough":
				if(browser.isSafari) {
					//取り消し線、Safari未対応のため Safari 2.0.4
					this.text_content.execCommand("bold", UI, param);
					var sel = this.getSelection();
					var range = this.createRange(sel);
					var el_ac = sel.anchorNode;
					var el_fc =sel.focusNode;	
					if(el_ac || el_fc) {
						if(el_fc) var el = this.getParentElementByTagName(el_fc, "span");
						if(el.style.fontWeight != "bold" && el_ac) {
							if(el_ac) el = this.getParentElementByTagName(el_ac, "span");
						}
						if(el) {
							el.style.fontWeight = "";
							el.style.textDecoration = "line-through";
						}
					}
				} else {
					this.text_content.execCommand(cmdID, UI, param);
				}
				break;
			default: 
				this.text_content.execCommand(cmdID, UI, param);
		}
		if(cmdID != "foce_addundolevel" && cmdID != "addundolevel")
			this.updateToolbar();
	},
	indentDiv: function(el, margin_px) {
		var style_value = Element.getStyle(el, "margin-left"); 
		var current_el = el;
		var current_style_value = style_value;
		while (current_style_value == null || current_style_value == "0px"){
			if(current_el.tagName == "BODY") break;
			current_el = current_el.parentNode;
			current_style_value = Element.getStyle(current_el, "margin-left");
		}
		if(current_el.tagName != "BODY") el = current_el,style_value = current_style_value;
		if(el.tagName == "BODY" || !this.isBlockElement(el)) return;
		if(style_value == null) {
			style_value = 0;
		}
		style_value = valueParseInt(style_value);
		var style_value = (style_value+margin_px < 0) ? 0 : style_value+margin_px;
		if(style_value == 0) {
			Element.setStyle(el,{"margin-left":''});
		} else {
			Element.setStyle(el,{"margin-left":style_value + 'px'});
		}
		//if (browser.isIE || browser.isOpera) el.innerHTML = el.innerHTML.strip();		//空白除去
	},
	//popupDialog: function(id, action, init) {
	//	Dialog(this.popupURL(id), action, init);
	//},
	popupURL: function(file) {
		var url = "";
		if (file.match(/^plugin:\/\/(.*?)\/(.*)/)) {
			var plugin = RegExp.$1;
			var popup = RegExp.$2;
			if (!/\.html$/.test(popup))
				popup += ".html";
			//url = _js_url + "plugins/" + plugin + "popups/" + popup;
			url = "./images/comp/textarea/" + plugin + "popups/" + popup;
			
		} else {
			url = "./images/comp/textarea/" + "popups/" + file;
			//url = _js_url + "popups/" + file;
		}
		return url;
	},
	//StartsBarリサイズ
	setStartsBarResizing: function(event) {
		this.setWidthAndHeight(true);
		if(this.editMode != "html") {
			if(browser.isSafari) this.text_style.visibility='hidden';
			else commonCls.displayNone(this.text);
			this.text_style.width= '0px';
			this.text_style.height= '0px';
		} else {
			commonCls.displayNone(this.textarea);
		}
		//this.htmlarea.style.display = "none";
		//this.resizeBox.style.display = "";
		
		this.setStartsBarDragGoEvent = this.setStartsBarDragGo.bindAsEventListener(this);
		this.setStartsBarDragStopEvent = this.setStartsBarDragStop.bindAsEventListener(this);
		
		Event.observe(document,"mousemove",this.setStartsBarDragGoEvent,false, this.id);
		Event.observe(document,"mouseup",this.setStartsBarDragStopEvent,false, this.id);
		Event.stop(event);
	},
	setStartsBarDragGo: function(event) {
		Event.stop(event);

		var offset = Position.cumulativeOffset(this.resizeBox);
		var EX1 = offset[0];
		var EY1 = offset[1];
		//var EY2 = this.resizeBox.offsetHeight + EY1;
		//var EX2 = this.resizeBox.offsetWidth + EX1;	
		
		if((Event.pointerY(event) - EY1) > this.htmlareaMinHeight){
			//this.resizeBoxSize = this.resizeBox.offsetHeight - Math.abs(Event.pointerY(event) - EY1) + "px";
			this.resizeBox.style.height = Math.abs((Event.pointerY(event) - EY1)) + "px";
		}
		if((Event.pointerX(event) - EX1) > this.htmlareaMinWidth){
			this.resizeBox.style.width = Math.abs((Event.pointerX(event) - EX1)) + "px";
		}
		this.htmlarea.style.width = this.resizeBox.offsetWidth + valueParseInt(Element.getStyle(this.resizeBox,"borderRightWidth"))  + valueParseInt(Element.getStyle(this.resizeBox,"borderLeftWidth")) + valueParseInt(Element.getStyle(this.resizeBox,"marginRight"))  + valueParseInt(Element.getStyle(this.resizeBox,"marginLeft")) + 'px';
		
		//15pxづつ移動
		commonCls.scrollMoveDrag(event, 15);
	},
	setStartsBarDragStop: function(event) {
		Event.stopObserving(document,"mousemove",this.setStartsBarDragGoEvent,false);
		Event.stopObserving(document,"mouseup",this.setStartsBarDragStopEvent,false);
		Event.stop(event);

		//リサイズ
		if(this.editMode != "html") {
			this.text_style.width= this.htmlareaOldWidth + 'px';
			this.text_style.height= this.htmlareaOldHeight + 'px';
			this.text_style.width = (valueParseInt(this.text_style.width) + (this.resizeBox.offsetWidth - this.htmlareaOldWidth)) + "px";
			this.text_style.height = (valueParseInt(this.text_style.height) + (this.resizeBox.offsetHeight - this.htmlareaOldHeight)) + "px";
		}
		if(!browser.isSafari) {
			this.textarea.style.width = (valueParseInt(Element.getStyle(this.textarea, "width")) + (this.resizeBox.offsetWidth - this.htmlareaOldWidth)) + "px";
			this.textarea.style.height = (valueParseInt(Element.getStyle(this.textarea, "height")) + (this.resizeBox.offsetHeight - this.htmlareaOldHeight)) + "px";
		} else {
			this.textarea.style.width = (this.resizeBox.offsetWidth) + "px";
			this.textarea.style.height = (this.resizeBox.offsetHeight) + "px";
		}
		//this.textarea.style.width = this.text_style.width;
		//this.textarea.style.height = this.text_style.height;
		if(this.editMode == "html") {
			commonCls.displayVisible(this.textarea);
		} else {
			if(browser.isSafari) this.text_style.visibility='visible';
			else commonCls.displayVisible(this.text);
		}
		this.setWidthAndHeight();
		//this.htmlarea.style.display = "";
		//this.resizeBox.style.display = "none";
		
		Element.remove(this.resizeBox);
		if(!(browser.isIE) && this.editMode == "edit") {
		//if (!(browser.isIE || browser.isOpera || browser.isSafari)) {
			// disable design mode before changing innerHTML
			try {
				this.text_content.designMode = "off";
				this.text_content.designMode = "on";
			} catch(e) {};
		}	
	},
	setWidthAndHeight: function(resize_flag) {
		if(this.editMode == "html") {
			var width = this.textarea.offsetWidth;
			var height = this.textarea.offsetHeight;
		} else {
			var width = this.text.clientWidth;
			var height = this.text.clientHeight;
		}
		this.htmlareaOldWidth = width;
		this.htmlareaOldHeight = height;
		if(resize_flag) {
			this.resizeBox = document.createElement("DIV");
			this.setTextAreaStyle(this.resizeBox);
			this.resizeBox.style.border= "1px dotted #666666";
			this.resizeBox.style.width = width + "px";
			this.resizeBox.style.height = height + "px";
			this.text.parentNode.insertBefore(this.resizeBox, this.text);
		}
	},
	changeEditMode: function() {
		if(this.oldeditMode == this.editMode)
			return;
		//if(this.statusbar.disabled==true)
		//	return;
		
		var mode = this.editMode;
		
		if(this.oldeditMode == "edit")
			Element.removeClassName(this.editModeBtn, "comptextarea_activeMode");
		else if(this.oldeditMode == "html")
			Element.removeClassName(this.htmlModeBtn, "comptextarea_activeMode");
		else
			Element.removeClassName(this.previewModeBtn, "comptextarea_activeMode");
		
		switch (mode) {
		    case "html":
				this.borderChange();
				this.textarea.value = this.getHTML();
				if(browser.isSafari) {
					this.text_style.visibility='hidden';
					this.text_style.width='0px';
					this.text_style.height='0px';
				} else {
					this.text_style.display = "none";
				}
				
				this.textarea.style.display = "block";
				this.textarea.style.visibility = "visible";
				Element.addClassName(this.htmlModeBtn, "comptextarea_activeMode");
				this.toolbarVisble("none");
				break;
		    case "edit":
				if(!(browser.isIE)) {
				//if (!(browser.isIE || browser.isOpera || browser.isSafari)) {
					// disable design mode before changing innerHTML
					try {
						this.text_content.designMode = "off";
					} catch(e) {};
				}
				//this.chgStyleSheet(false);
				Element.addClassName(this.text_content.body, "comptextareat_content");
				var html = this.getHTML();
				var html = this.getHTML();
				
				if(browser.isIE || browser.isSafari) {
					//SCRIPTタグをinnerHTMLした場合、IEでは削除されるため
					this.text_content.body.innerHTML = "<br />" + html;	//先頭にScriptタグがあった場合、なぜかIEがScriptタグを削除するため
					this.text_content.body.removeChild(this.text_content.body.firstChild);
				} else {
					this.text_content.body.innerHTML =html;
				}
				if(browser.isSafari) this.text_style.visibility='visible';
				else this.text_style.display = "";
				this.text_style.width= this.htmlareaOldWidth + 'px';
				this.text_style.height= this.htmlareaOldHeight + 'px';
				
				this.textarea.style.display = "none";
				//if (!(browser.isIE || browser.isOpera || browser.isSafari)) {
				if(!(browser.isIE)) {
					// we need to refresh that info for Moz-1.3a
					try {
						this.text_content.designMode = "on";
					} catch(e) {};
				}else{
					this.text_content.body.contentEditable = true;
				}
				Element.addClassName(this.editModeBtn, "comptextarea_activeMode");
				this.toolbarVisble();
				this.borderChange();
				break;
			case "preview":
				//if (!(browser.isIE || browser.isOpera || browser.isSafari)) {
				if(!(browser.isIE)) {
					// disable design mode before changing innerHTML
					try {
						this.text_content.designMode = "off";
					} catch(e) {};
				}else {
					this.text_content.body.contentEditable = false;
				}
				//this.chgStyleSheet();
				Element.removeClassName(this.text_content.body, "comptextareat_content");
				var html = this.getHTML();
				if(browser.isIE || browser.isSafari) {
					//SCRIPTタグをinnerHTMLした場合、IEでは削除されるため
					this.text_content.body.innerHTML = "<br />" + html;	//先頭にScriptタグがあった場合、なぜかIEがScriptタグを削除するため
					this.text_content.body.removeChild(this.text_content.body.firstChild);
				} else {
					this.text_content.body.innerHTML =html;
				}
				if(browser.isSafari) this.text_style.visibility='visible';
				else this.text_style.display = "";
				this.text_style.width= this.htmlareaOldWidth + 'px'
				this.text_style.height= this.htmlareaOldHeight + 'px'
				
				//this.text_style.display = "block";
				this.textarea.style.display = "none";
				Element.addClassName(this.previewModeBtn, "comptextarea_activeMode");
				this.toolbarVisble("none");
				this.borderChange();
				break;
			default:
				alert("Mode <" + mode + "> not defined!");
				return false;
		}
		this.editMode = mode;
		this.forceRedraw();
		this.focusEditor(true);
		
		//for (var i in this.plugins) {
		//	var plugin = this.plugins[i].instance;
		//	if (typeof plugin.onMode == "function") plugin.onMode(mode);
		//}
	},
	borderChange: function(set_mode) {
		if(set_mode != undefined) {
			var mode = set_mode;
		} else {
			var mode = this.editMode;
		}	
		//テーブルのボーダーが0の場合、見せ方を変更する
		var tableList = this.text_content.getElementsByTagName("TABLE");
		for (var i = 0,tableLen = tableList.length; i < tableLen; i++) {
			if (tableList[i].border == 0 || Element.getStyle(tableList[i], "borderWidth") == "0px")	{
				if (mode == "edit") {
					tableList[i].style.border = "1px dotted #666666";
				} else {
					tableList[i].style.border = "0px";
				}
				for( var k = 0; k < tableList[i].rows.length; k++ ) {
					for( var j = 0; j < tableList[i].rows[k].cells.length; j++ ) {
						if (mode == "edit") {
							tableList[i].rows[k].cells[j].style.border = "1px dotted #666666";
						}else {
							tableList[i].rows[k].cells[j].style.border = "0px";
						}
					}
				}
				if (mode == "edit" && set_mode == undefined) {
					this.tableRedraw(tableList[i]);
				}
			}
		}
		//PreviewでAタグをクリックしてもキャンセルする処理を入れる
		var aList = this.text_content.getElementsByTagName("A");
		for (var i = 0,aLen = aList.length; i < aLen; i++) {
			if(aList[i].target != "_blank") {
				//if (this.editMode == "edit") {
				//	aList[i].onclick = "";
				//}else{
					aList[i].onclick = function(){return false;};
				//}
			}
		}
	},
	tableRedraw: function(table) {
		//表の再描画処理 FireFox 反映されないため
		if(!(browser.isIE || browser.isOpera)) {
			commonCls.displayNone(table);
			setTimeout(function() {
				commonCls.displayVisible(table);
			}.bind(this), 0);
		}
	},
	// retrieve the HTML
	getHTML: function(set_mode) {
		if(set_mode != undefined) {
			var mode = set_mode;
			if(mode == "preview") mode = ((this.editMode == "edit" || this.editMode == "preview") ? "edit" : "html");
			if(set_mode == "preview") this.borderChange("preview");
		} else if(this.editMode == "preview")
			var mode = ((this.oldeditMode == "edit" || this.oldeditMode == "preview") ? "edit" : "html");
		else if(this.oldeditMode == "preview")
			var mode = "edit";
		else
			var mode = ((this.editMode == "edit") ? "html" : "edit");
		switch (mode) {
		    case "edit"  :
				var html = this.getHTMLWrapper(this.text_content.body, false, this);
				html = this.setFormatHtml(html);
				return html;
			case "html" : 
				
				return this.textarea.value;
		    default	    : alert("Mode <" + mode + "> not defined!");
		}
		return false;
	},
	//テキストエリア取得
	getTextArea: function() {
		var html = this.getHTML("preview");
		if(this.editMode == "html") {
			var html = this.getHTML("preview");
			if(browser.isIE || browser.isSafari) {
				//SCRIPTタグをinnerHTMLした場合、IEでは削除されるため
				this.text_content.body.innerHTML = "<br />" + html;	//先頭にScriptタグがあった場合、なぜかIEがScriptタグを削除するため
				this.text_content.body.removeChild(this.text_content.body.firstChild);
			} else {
				this.text_content.body.innerHTML =html;
			}
			html = this.getHTMLWrapper(this.text_content.body, false, this);
			html = this.setFormatHtml(html);
		}	
		return html;
	},
	//テキストエリアクリアー
	clearTextArea: function() {
		this.textarea = null;
		return false;
	},
	getHTMLWrapper: function(root, outputRoot, editor) {
		try{
	        var html = "";
			switch (root.nodeType) {
			    case 1: // Node.ELEMENT_NODE
			    case 11: // Node.DOCUMENT_FRAGMENT_NODE
					var closed;
					var i;
					var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : '';
					if (root_tag == 'br' && !root.nextSibling){
						if(root.parentNode.tagName != "TD") {
							html += "<br />";	//br挿入
						}
						//html += "&nbsp;";	//nbsp;挿入
						break;
					}
					if (outputRoot)
						outputRoot = !(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(root_tag));
					if ((browser.isIE || browser.isOpera) && root_tag == "head") {
						if (outputRoot)
							html += "<head>";
						// lowercasize
						var save_multiline = RegExp.multiline;
						RegExp.multiline = true;
						var txt = root.innerHTML.replace(this.RE_tagName, function(str, p1, p2) {
							return p1 + p2.toLowerCase();
						});
						RegExp.multiline = save_multiline;
						html += txt;
						if (outputRoot)
							html += "</head>";
						break;
					} else if (outputRoot) {
						//iframeの場合<iframe src="XXX" />と変換してしまうとjavascriptの読み込みがストップされるようなので
						//中の値があるなしにかかわらず、閉じタグを挿入する
						//closed = (!(root.hasChildNodes() || this.needsClosingTag(root)));
						if(root.tagName.toLowerCase() == "iframe") {
							closed = false;
						} else {
							closed = (!(root.hasChildNodes() || this.needsClosingTag(root)));
						}
						html = "<" + root.tagName.toLowerCase();
						var attrs = root.attributes;
						for (i = 0; i < attrs.length; ++i) {
							var a = attrs.item(i);
							if (!a.specified) {
								continue;
							}
							var name = a.nodeName.toLowerCase();
							if (/_moz_editor_bogus_node/.test(name)) {
								html = "";
								break;
							}
							if (/_moz|contenteditable|_msh/.test(name)) {
								// avoid certain attributes
								continue;
							}
							var value;
							if (name != "style") {
								// IE5.5 reports 25 when cellSpacing is
								// 1; other values might be doomed too.
								// For this reason we extract the
								// values directly from the root node.
								// I'm starting to HATE JavaScript
								// development.  Browser differences
								// suck.
								//
								// Using Gecko the values of href and src are converted to absolute links
								// unless we get them using nodeValue()
								if (typeof root[a.nodeName] != "undefined" && name != "href" && name != "src" && !/^on/.test(name)) {
									value = root[a.nodeName];
								} else {
									value = a.nodeValue;
									// IE seems not willing to return the original values - it converts to absolute
									// links using a.nodeValue, a.value, a.stringValue, root.getAttribute("href")
									// So we have to strip the baseurl manually :-/
									//if ((browser.isIE || browser.isOpera) && (name == "href" || name == "src")) {
									//	value = this.stripBaseURL(value);
									//}
								}
							} else { // IE fails to put style in attributes list
								// FIXME: cssText reported by IE is UPPERCASE
								value = root.style.cssText;
							}
							if (/(_moz|^$)/.test(value)) {
								// Mozilla reports some special tags
								// here; we don't need them.
								continue;
							}
							if(browser.isIE) {
						       if(a.nodeName == "_extended" || value != null && value != "" && typeof value=="function") {
						       		//変数汚染されるため追加
									continue;
								}
							}
							html += " " + name + '="' + value + '"';
						}
						if (html != "") {
							html += closed ? " />" : ">";
						}
					}
					if(browser.isIE && root.tagName == "SCRIPT") {
						html += root.innerHTML.trim();
					} else {
						for (var i = root.firstChild; i; i = i.nextSibling) {
							html += this.getHTMLWrapper(i, true, editor);
						}
					}
					if (outputRoot && !closed) {
						html += "</" + root.tagName.toLowerCase() + ">";
					}
					break;
				case 3: // Node.TEXT_NODE
					//先頭に改行があれば取り除く
					if (!root.data.match(/^<!--/)) {
						root.data = root.data.replace('\n','');
					}
					// If a text node is alone in an element and all spaces, replace it with an non breaking one
					// This partially undoes the damage done by moz, which translates '&nbsp;'s into spaces in the data element
					/* if ( !root.previousSibling && !root.nextSibling && root.data.match(/^\s*$/i) ) html = '&nbsp;';
					   else */
					html = /^script|style|table|tbody|tr$/i.test(root.parentNode.tagName) ? root.data : this.htmlEncode(root.data);
					//html = /^script|style$/i.test(root.parentNode.tagName) ? root.data : this.htmlEncode(root.data);
					break;
			    case 4: // Node.CDATA_SECTION_NODE
					// FIXME: it seems we never get here, but I believe we should..
					//        maybe a browser problem?--CDATA sections are converted to plain text nodes and normalized
					// CDATA sections should go "as is" without further encoding
					html = "<![CDATA[" + root.data + "]]>";
					break;
			    case 8: // Node.COMMENT_NODE
			    	html = "<!--" + root.data + "-->";
					break;		// skip comments, for now.
			}
			return html;
	    }
	    catch(e){
	        alert('Your Document is not well formed. Check JavaScript console for details.');
	        return this.text.contentWindow.document.body.innerHTML;
	    }
	},
	needsClosingTag:  function(el) {
		this.closingTags = " head script style div span tr td tbody table em strong b i code cite dfn abbr acronym font a title ";
		return el && el.nodeType == 1 && (this.closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
	},
	// performs HTML encoding of some given string
	htmlEncode: function(str) {
		// we don't need regexp for that, but.. so be it for now.
		str = str.replace(/&/ig, "&amp;");
		str = str.replace(/</ig, "&lt;");
		str = str.replace(/>/ig, "&gt;");
		str = str.replace(/\x22/ig, "&quot;");
		// \x22 means '"' -- we use hex reprezentation so that we don't disturb
		// JS compressors (well, at least mine fails.. ;)
		
		//&nbsp;処理追加
		////if(!browser.isSafari) str = str.replace(/[^\S\n\r\t\f]/ig, "&nbsp;");
		
		return str;
	},
	focusEditor: function(first_flag) {
		switch (this.editMode) {
		    // notice the try { ... } catch block to avoid some rare exceptions in FireFox
		    // (perhaps also in other Gecko browsers). Manual focus by user is required in
	        // case of an error. Somebody has an idea?
		    case "edit" : 
			case "preview" :
						try {
							if(!browser.isOpera) {
							//if(browser.isGecko) {
								//	this.toolbar.focus();
								this.text.contentWindow.focus();
								if(first_flag) {
								
									if (browser.isIE) {
										//this.text.contentWindow.document.body.focus();
										var range = this.text_content.body.createTextRange();
										range.collapse();
										range.move('character', 0);	//this.text_content.body.innerHTML.length
										range.select();
									} else {
										var sel = this.getSelection();
										range = this.text_content.createRange();
										range.setEnd(this.text_content.body, 0);
										range.setStart(this.text_content.body, 0);
										sel.addRange(range);
									}
								}
							} else {
								this.text.contentWindow.document.body.blur();
								this.text.contentWindow.document.body.focus();
							}
						} catch (e) {}
						break;
		    case "html": try { this.textarea.focus(); } catch (e) {} break;
		    default	   : alert("ERROR: mode " + this.editMode + " is not defined");
		}
		return this.text_content;
	},
	setFormatHtml: function(html) {
		html = html.replace(new RegExp('<br />', 'g'), "<br />\n");
		////html = html.replace(new RegExp('(?:[^\n]?)<(table[^>]*)>', 'g'), "\n<$1>");
		html = html.replace(new RegExp('</(ol|ul|li|div|table|pre|td)>', 'g'), "</$1>\n");
		html = html.replace(new RegExp('<(ol|table[^>]*|tbody|tr[^>]*)>', 'g'), "<$1>\n");
		html = html.replace(new RegExp('( *)</(tr[^>]*)>', 'g'), "   </$2>\n");
		html = html.replace(new RegExp('( *)</(tbody[^>]*)>', 'g'), "   </$2>\n");
		html = html.replace(new RegExp('\n<(li|tbody|tr[^>]*)>', 'g'), "\n   <$1>");
		html = html.replace(new RegExp('\n<(td[^>]*)>', 'g'), "\n      <$1>");
		
		//html = html.replace(new RegExp('([\s]*)<(ol|table[^>]*|tbody|tr[^>]*)>', 'g'), "$1<$2>\n$1   ");
		//html = html.replace(new RegExp('([\s]*)<(li|tbody|tr[^>]*)>', 'g'), "$1<$1>\n$1   ");
		////html = html.replace(new RegExp('([\s]*)<(td[^>]*)>', 'g'), "<$1>");
		//html = html.replace(new RegExp('([\s]*)(\s{3})<(td[^>]*)>([\s|\S]*)</(td)>', 'g'), "<$3>$4</$5>\n$1");
		//html = html.replace(new RegExp('([\s]*)</(tbody|tr[^>]*)>', 'g'), "$1</$2>\n");
		//html = html.replace(new RegExp('</(ol|ul|li|div|table|pre)>', 'g'), "</$1>\n");
		
		
		////html = html.replace(new RegExp('<p([^>]*)>', 'g'), "<div$1>");
		////html = html.replace(new RegExp('</p>', 'g'), "</div>\n");

		html = html.replace(new RegExp('<div([^>]*)></div>\n(.)', 'g'), "<div$1>&nbsp;</div>\n$2");
		
		//html = html.replace(new RegExp('<div([^>]*)></div>\n(.)', 'g'), "<br />\n$2");
		
		//html = html.replace(new RegExp('<div([^>]*)></div>', 'g'), "<div$1> </div>");
		
		//html = html.replace(new RegExp('(?:<table[^>]*>)(?:(?:(?:(?!</?table[^>]*>).)*)|(?R))*</table>', 'g'), "test\n");
		
		//html = html.replace(/(?:<table[^>]*>)(?:(?:(?:(?!<\/?table[^>]*>).)*)|(?R))*<\/table>/ig,'aaa');
		//html = html.replace(/<table([^>]*)>/ig,'<table$1>\n');
		//html = html.replace(/<\/table>/ig,'</table>\n');
		//html = html.replace(/<tbody>/ig,'   <tbody>\n');
		//html = html.replace(/<\/tbody>/ig,'   </tbody>\n');
		//html = html.replace(/<tr([^>]*)>/ig,'   <tr$1>\n');
		//html = html.replace(/<\/tr>/ig,'   </tr>\n');
		////html = html.replace(/<td([^>]*)>([^<]*)<\/td>/ig,'      <td$1>$2</td>\n');
		//html = html.replace(/<td([^>]*)>/ig,'      <td$1>\n');
		//html = html.replace(/<\/td>/ig,'\n      </td>\n');
		
		//html = html.replace(new RegExp('<table([\s|\S]*)>', ''), "<table$1>\n");
		//html = html.replace(/<table([^>]+)[^>]*>([^<]+)<\/table>/ig,'<table$1>\n$2</table>'); 
		//html = html.replace(/<table([^>]*)>([.]+)<\/table>/ig,'<table$1>\n$2</table>'); 
		
		//html = html.replace(/{<table([\s|\S]*)>}?/ig,'<table$1>\\n'); 
		//html = html.replace(/<\/table>/ig,'</table>\n');
		return html;
	},
	/** Returns a node after which we can insert other nodes, in the current
	 * selection.  The selection is removed.  It splits a text node, if needed.
	 */
	insertNodeAtSelection: function(toBeInserted) {
		if (!browser.isIE) {
			var sel = this.getSelection();
			var range = this.createRange(sel);
			// remove the current selection
			sel.removeAllRanges();
			range.deleteContents();
			var node = range.startContainer;
			var pos = range.startOffset;
			switch (node.nodeType) {
			    case 3: // Node.TEXT_NODE
				// we have to split it at the caret position.
				if (toBeInserted.nodeType == 3) {
					// do optimized insertion
					node.insertData(pos, toBeInserted.data);
					range = this.createRange();
					range.setEnd(node, pos + toBeInserted.length);
					range.setStart(node, pos + toBeInserted.length);
					sel.addRange(range);
				} else {
					node = node.splitText(pos);
					var selnode = toBeInserted;
					if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
						selnode = selnode.firstChild;
					}
					node.parentNode.insertBefore(toBeInserted, node);
					this.selectNodeContents(selnode);
					this.updateToolbar();
				}
				break;
			    case 1: // Node.ELEMENT_NODE
				var selnode = toBeInserted;
				if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
					selnode = selnode.firstChild;
				}
				node.insertBefore(toBeInserted, node.childNodes[pos]);
				this.selectNodeContents(selnode);
				this.updateToolbar();
				break;
			}
		} else {
			return null;	// this function not yet used for IE <FIXME>
		}
	},
	// Selects the contents inside the given node
	selectNodeContents: function(node, pos) {
		this.focusEditor();
		this.forceRedraw();
		var range;
		var collapsed = (typeof pos != "undefined");
		if (browser.isIE || browser.isOpera) {
			range = this.text_content.body.createTextRange();
			range.moveToElementText(node);
			(collapsed) && range.collapse(pos);
			range.select();
		} else {
			var sel = this.getSelection();
			range = this.text_content.createRange();
			range.selectNodeContents(node);
			(collapsed) && range.collapse(pos);
			if (!browser.isSafari) {
				sel.removeAllRanges();
				sel.addRange(range);
			}
		}
	},
	//---------------------------------
	//Table Operation
	//---------------------------------
	// this function gets called when some button from the TableOperations toolbar
	// was pressed.
	tableButtonPress: function(button_id) {
		var editor = this.text_content;
		var thisobj = this;
		var mozbr = (browser.isGecko) ? "&nbsp;" : "";
		
		//ダイアログを閉じる
		this.closePopup("tableinsertmenu");
		this.closePopup("tablemenu");

		// helper function that clears the content in a table row
		function clearRow(tr) {
			var tds = tr.getElementsByTagName("td");
			for (var i = tds.length; --i >= 0;) {
				var td = tds[i];
				td.rowSpan = 1;
				td.innerHTML = mozbr;
			}
		};

		function splitRow(td) {
			var n = parseInt("" + td.rowSpan);
			var nc = parseInt("" + td.colSpan);
			td.rowSpan = 1;
			tr = td.parentNode;
			var itr = tr.rowIndex;
			var trs = tr.parentNode.rows;
			var index = td.cellIndex;
			while (--n > 0) {
				tr = trs[++itr];
				var otd = thisobj.text_content.createElement("td");
				copytdStyle(otd,td);
				otd.colSpan = td.colSpan;
				otd.innerHTML = mozbr;
				tr.insertBefore(otd, tr.cells[index]);
			}
			thisobj.forceRedraw();
			thisobj.updateToolbar();
		};

		function splitCol(td) {
			var nc = parseInt("" + td.colSpan);
			td.colSpan = 1;
			tr = td.parentNode;
			var ref = td.nextSibling;
			while (--nc > 0) {
				var otd = thisobj.text_content.createElement("td");
				copytdStyle(otd,td);
				otd.rowSpan = td.rowSpan;
				otd.innerHTML = mozbr;
				tr.insertBefore(otd, ref);
			}
			thisobj.forceRedraw();
			thisobj.updateToolbar();
		};

		function splitCell(td) {
			var nc = parseInt("" + td.colSpan);
			splitCol(td);
			var items = td.parentNode.cells;
			var index = td.cellIndex;
			while (nc-- > 0) {
				splitRow(items[index++]);
			}
		};

		function copytdStyle(td,copytd) {
			td.style.border = copytd.style.border;
			td.style.backgroundColor = copytd.style.backgroundColor;
		}

		function selectNextNode(el) {
			var node = el.nextSibling;
			while (node && node.nodeType != 1) {
				node = node.nextSibling;
			}
			if (!node) {
				node = el.previousSibling;
				while (node && node.nodeType != 1) {
					node = node.previousSibling;
				}
			}
			if (!node) {
				node = el.parentNode;
			}
			thisobj.selectNodeContents(node);
		};

		switch (button_id) {
			// ROWS
		    case "insert_row_before":
		    case "insert_row_after":
				var tr = this.getClosest("tr");
				if (!tr) {
					break;
				}
				var otr = tr.cloneNode(true);
				clearRow(otr);
				tr.parentNode.insertBefore(otr, /after/.test(button_id) ? tr.nextSibling : tr);
				this.forceRedraw();
				this.focusEditor();
				break;
		    case "row_delete":
				var tr = this.getClosest("tr");
				if (!tr) {
					break;
				}
				var par = tr.parentNode;
				if (par.rows.length == 1) {
					//テーブル削除処理
					var el_table = this.getClosest("table");
					Element.remove(el_table);
					this.forceRedraw();
					this.focusEditor();
					break;
				}
				// set the caret first to a position that doesn't
				// disappear.
				selectNextNode(tr);
				par.removeChild(tr);
				this.forceRedraw();
				this.focusEditor();
				this.updateToolbar();
				break;
		    case "spilit_row":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				splitRow(td);
				break;

			// COLUMNS

		    case "insert_col_before":
		    case "insert_col_after":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				var rows = td.parentNode.parentNode.rows;
				var index = commonCls.cellIndex(td); //td.cellIndex;
				
				for (var i = rows.length; --i >= 0;) {
					var tr = rows[i];
					var ref = tr.cells[index];
					if(ref) {
						var index_ref = commonCls.cellIndex(ref);
						/*
						var insertbefore_flag = true;
						
						if((/after/.test(button_id))) {
							if(ref.nextSibling) {
								ref = tr.cells[index + 1];
							} else {
								insertbefore_flag = false;
							}	
						}
						*/
						//var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)];
						
						//if(insertbefore_flag) {
						//	var otd = this.text_content.createElement("td");
						//	ref.insertBefore(otd, ref);
						//} else {
						//	var otd = ref.parentNode.insertCell(index + 1);	
						//	//ref.appendChild(otd);
						//}
						if(button_id == "insert_col_before") {
							var insert_index = index_ref;
						} else {
							var insert_index = index_ref + 1;
						}
						var otd = tr.insertCell(insert_index);	
						otd.innerHTML = mozbr;
						//スタイルコピー
						otd.style.border = td.style.border;
						otd.style.backgroundColor = td.style.backgroundColor;
					}
				}
				this.focusEditor();
				break;
		    case "spilit_col":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				splitCol(td);
				break;
		    case "col_delete":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				var index = td.cellIndex;
				if (td.parentNode.cells.length == 1) {
					//テーブル削除処理
					var el_table = this.getClosest("table");
					Element.remove(el_table);
					this.forceRedraw();
					this.focusEditor();
					break;
				}
				// set the caret first to a position that doesn't disappear
				selectNextNode(td);
				var rows = td.parentNode.parentNode.rows;
				for (var i = rows.length; --i >= 0;) {
					var tr = rows[i];
					tr.removeChild(tr.cells[index]);
				}
				this.forceRedraw();
				this.focusEditor();
				this.updateToolbar();
				break;

			// CELLS
		    case "spilit_cell":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				splitCell(td);
			break;
		    case "insert_cell_before":
		    case "insert_cell_before":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				var tr = td.parentNode;
				var otd = editor._doc.createElement("td");
				otd.innerHTML = mozbr;
				tr.insertBefore(otd, /after/.test(button_id) ? td.nextSibling : td);
				this.forceRedraw();
				this.focusEditor();
				break;
		    case "cell_delete":
				var td = this.getClosest("td");
				if (!td) {
					break;
				}
				if (td.parentNode.cells.length == 1) {
					//テーブル削除処理
					var el_table = this.getClosest("table");
					Element.remove(el_table);
					this.forceRedraw();
					this.focusEditor();
					break;
				}
				// set the caret first to a position that doesn't disappear
				selectNextNode(td);
				td.parentNode.removeChild(td);
				this.forceRedraw();
				this.updateToolbar();
				break;
			case "marge_cell":
				// !! FIXME: Mozilla specific !!
				var td = this.getClosest("td");
				var sel = this.getSelection();
				var range, i = 0;
				var rows = [];
				var row = null;
				var cells = null;
				if (sel.rangeCount == 1 || (browser.isIE || browser.isOpera)) {
					//IE Or 選択範囲が一つならば
					//ダイアログ表示
					this.showTableMergeDialog(td); break;
				} else{
					try {
						while (range = sel.getRangeAt(i++)) {
							var td = range.startContainer.childNodes[range.startOffset];
							if (td.parentNode != row) {
								row = td.parentNode;
								(cells) && rows.push(cells);
								cells = [];
							}
							cells.push(td);
						}
					} catch(e) {/* finished walking through selection */}
					rows.push(cells);
					var HTML = "";
					for (i = 0; i < rows.length; ++i) {
						// i && (HTML += "<br />");
						var cells = rows[i];
						for (var j = 0; j < cells.length; ++j) {
							// j && (HTML += "&nbsp;");
							var cell = cells[j];
							if(cell.innerHTML == "<br>" || cell.innerHTML == "<br />" || cell.innerHTML == "&nbsp;") {
								//BRタグのみ
								;
							}else
								HTML += cell.innerHTML;
							
							(i || j) && (cell.parentNode.removeChild(cell));
						}
					}
					var td = rows[0][0];
					if(HTML == "")
						HTML = "<br />";
					td.innerHTML = HTML;
					td.rowSpan = rows.length;
					td.colSpan = rows[0].length;
					this.selectNodeContents(td);
					this.forceRedraw();
					this.focusEditor();
				}
				break;
		    default:
			alert("Button [" + button_id + "] not yet implemented");
		}
	},
	// retrieves the closest element having the specified tagName in the list of
	// ancestors of the current selection/caret.
	getClosest: function(tagName) {

		//var editor = this.el;
		var ancestors = this.el_array; //this.getAllAncestors.bind(editor);
		var ret = null;
		tagName = ("" + tagName).toLowerCase();
		for (var i = 0; i < ancestors.length; ++i) {
			var el = ancestors[i];
			if (el.tagName.toLowerCase() == tagName) {
				ret = el;
				break;
			}
		}
		return ret;
	},
	getColorCode: function(el , property_name) {
		var ret = commonCls.getColorCode(el, property_name);
		if(property_name == "color") {
			//親と同じ色（継承されているので、空を代入）
			var color = commonCls.getColorCode(document.body, property_name);
			if(ret == color) ret = "";
		}
		return (ret == "transparent") ? "" : ret;
	},
	//stripBaseURL: function(string) {
		//var baseurl = this.config.baseURL;

		// strip to last directory in case baseurl points to a file
		//baseurl = baseurl.replace(/[^\/]+$/, '');
		//var basere = new RegExp(baseurl);
		//string = string.replace(basere, "");

		// strip host-part of URL which is added by MSIE to links relative to server root
		//baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1');
		//basere = new RegExp(baseurl);
		//return string.replace(basere, "");
		//TODO:後に修正
		//return string;
	//},
	/* Zip形式に保存 */
	saveZip: function() {
		var frm = document.createElement('form');
		frm.innerHTML = '<input type="hidden" name="content" value="">';
		document.body.appendChild(frm);
		frm.method = "post";
		frm.action = _js_url +"/include/comp/textarea/zip.php";
		frm.content.value = this.getHTML("edit");
		frm.submit();
		document.body.removeChild(frm);
		//window.location =  _js_url +"/include/comp/textarea/zip.php?content="+encodeURIComponent(this.getHTML("edit"));
		
	},
	setUploadAction: function(action) {
		this.uploadAction['image'] = action;
		this.uploadAction['file'] = action;
	},
	setTokenName: function(name) {
		this.uploadAction['token'] = name;
	},
	upload: function(targetDocument) {
		if (targetDocument.getElementById("attachment_form") == null) {
			var div = targetDocument.createElement('div');
			div.innerHTML='<iframe src="about:blank" id="attachment_form" name="attachment_form" style="width:0px;height:0px;"></iframe>';
			targetDocument.body.appendChild(div);
			var create_flag = true;
		}				
		var postForm = targetDocument.getElementsByTagName("form")[0];
		postForm.target = "attachment_form";
		postForm.action = this.uploadAction['file'];
		postForm.method = "post";
		if (create_flag) {
			//token set
			var name = this.uploadAction['token'];
			var form_el = this.textarea.form;
			var value = form_el[this.uploadAction['token']].value;
			var input=targetDocument.createElement('input');
			input.setAttribute("name",name,1);
			input.setAttribute("type","hidden",1);
			input.value = value;
			postForm.appendChild(input);
			//block_id
			var value = form_el.block_id.value;
			var input=targetDocument.createElement('input');
			input.setAttribute("name","block_id",1);
			input.setAttribute("type","hidden",1);
			input.value = value;
			postForm.appendChild(input);
		}
		postForm.submit();
	}
}
