      1 ﻿
      2 /**
      3  * @name	CeL function for web
      4  * @fileoverview
      5  * 本檔案包含了 web 的 functions。
      6  * @since
      7  */
      8
      9 /*
     10 http://www.comsharp.com/GetKnowledge/zh-CN/It_News_K902.aspx
     11 http://www.nczonline.net/blog/2010/01/12/history-of-the-user-agent-string/
     12 當 IE 初次推出它們的 User Agent 標誌的時候，是這個樣子：
     13 MSIE/3.0 (Win95; U)
     14
     15 TODO:
     16 don't use .innerHTML
     17 通盤確認所有 HTMLElement 變數已經設成 null
     18
     19
     20 功能探測 vs 瀏覽器探測
     21 http://www.comsharp.com/GetKnowledge/zh-CN/It_News_K987.aspx
     22 Mark Pilgrim 有一個清單，它可以讓你探測任何功能。
     23 http://diveintohtml5.org/everything.html
     24
     25 */
     26
     27 if (typeof CeL === 'function')
     28 CeL.setup_module('interact.DOM',
     29 {
     30 require : 'data.code.compatibility.is_DOM|data.split_String_to_Object',
     31 code : function(library_namespace, load_arguments) {
     32
     33 //	requiring
     34 var is_DOM,split_String_to_Object;
     35 eval(library_namespace.use_function(this));
     36
     37
     38 /**
     39  * null module constructor
     40  * @class	web 的 functions
     41  */
     42 CeL.interact.DOM
     43 = function() {
     44 	//	null module constructor
     45 };
     46
     47 /**
     48  * for JSDT: 有 prototype 才會將之當作 Class
     49  */
     50 CeL.interact.DOM
     51 .prototype = {
     52 };
     53
     54
     55
     56
     57
     58
     59 /*
     60 	HTML only	-------------------------------------------------------
     61 */
     62
     63 /**
     64  * NodeType: const unsigned short.
     65  * @see
     66  * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-1950641247
     67  * http://www.w3.org/TR/DOM-Level-2-Core/core.html
     68  * ELEMENT_NODE,ATTRIBUTE_NODE,TEXT_NODE,CDATA_SECTION_NODE,ENTITY_REFERENCE_NODE,ENTITY_NODE,PROCESSING_INSTRUCTION_NODE,COMMENT_NODE,DOCUMENT_NODE,DOCUMENT_TYPE_NODE,DOCUMENT_FRAGMENT_NODE,NOTATION_NODE
     69  * @inner
     70  */
     71 var ELEMENT_NODE = 1,
     72 	TEXT_NODE = 3,
     73 	DOCUMENT_NODE = 9;
     74
     75 if(is_DOM('document') &&
     76 		//	IE8: undefined
     77 		!isNaN(document.ELEMENT_NODE))
     78 	ELEMENT_NODE = document.ELEMENT_NODE,
     79 	TEXT_NODE = document.TEXT_NODE,
     80 	DOCUMENT_NODE = document.DOCUMENT_NODE;
     81
     82 //	IE 中 Object.prototype.toString.call(HTML Element)==='[object Object]', 得用 ''+node
     83 var get_object_type = Object.prototype.toString,
     84 element_pattern = /^\[object HTML([A-U][A-Za-z]{1,15})?Element\]$/;
     85
     86
     87
     88 CeL.interact.DOM
     89 .
     90 /**
     91  * 判斷是否為 HTML Element。
     92  * @param	value	value to test
     93  * @return	{Boolean}	value is HTML Element
     94  * @since	2010/6/23 02:32:41
     95  * @memberOf	CeL.interact.DOM
     96  * @see
     97  * http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037,
     98  * http://www.w3.org/DOM/
     99  */
    100 is_HTML_element = function(value) {
    101 	// return get_object_type.call(value).indexOf('[object HTML')===0;
    102 	return element_pattern.test(get_object_type.call(value))
    103 		|| '[object Text]' === get_object_type.call(value)
    104 		&& value.nodeType === TEXT_NODE;
    105 	// return get_object_type.call(value).match(element_pattern);
    106 };
    107
    108 CeL.interact.DOM
    109 .
    110 /**
    111  * 判斷為指定 nodeType 之 HTML Element。
    112  * @param	value	value to test
    113  * @param	type	type
    114  * @return	{Boolean}	value is the type of HTML Element
    115  * @since	2010/6/23 02:32:41
    116  * @memberOf	CeL.interact.DOM
    117  * @see
    118  * http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037,
    119  * http://www.w3.org/DOM/
    120  */
    121 is_HTML_element_type = function(value, type) {
    122 	return type === TEXT_NODE ?
    123 			'[object Text]' === get_object_type.call(value) && value.nodeType === TEXT_NODE
    124 			: element_pattern.test(get_object_type.call(value)) && value.nodeType === type;
    125 };
    126
    127 CeL.interact.DOM
    128 .
    129 /**
    130  * 判斷為 HTML Element。
    131  * @param	value	value to test
    132  * @return	{Boolean}	value is HTML Element
    133  * @since	2010/6/23 02:32:41
    134  * @memberOf	CeL.interact.DOM
    135  * @see
    136  * http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037,
    137  * http://www.w3.org/DOM/
    138  */
    139 is_element_node = function(value) {
    140 	//library_namespace.debug('Test '+get_object_type.call(value)+' '+((typeof value==='object'||typeof value==='function')&&value.nodeType||'')+': '+element_pattern.test(get_object_type.call(value))+','+(value.nodeType === 1));
    141 	return element_pattern.test(get_object_type.call(value)) && value.nodeType === ELEMENT_NODE;
    142 };
    143
    144
    145 /*
    146
    147 IE5DOM @ IE9 test:
    148 IE7DOM @ IE9 test:
    149 node <DIV>: type object, toString.call: [object Object], ""+node: [object], nodeType: 1:
    150
    151 IE8:
    152 IE8DOM @ IE9 test:
    153 IE9DOM @ IE9 test:
    154 node <DIV>: type object, toString.call: [object Object], ""+node: [object HTMLDivElement], nodeType: 1:
    155
    156 IE8:
    157 node <A>: type object, toString.call: [object Object], ""+node: , nodeType: 1:
    158 node <OBJECT>: type object, toString.call: [object Object], ""+node: [object], nodeType: 1:
    159
    160 */
    161 function show_node(node) {
    162 	if(_.is_element_node(node))
    163 		library_namespace.debug('node'
    164 			+ (node.tagName ? ' <' + node.tagName
    165 					+ (node.id ? '#' + node.id : '') + '>' : '') + ': type '
    166 			+ typeof node + ', toString.call: ' + get_object_type.call(node)
    167 			+ ', ""+node: ' + ('' + node) + ', nodeType: ' + node.nodeType
    168 			+ ('innerHTML' in node ? ': ' + node.innerHTML : ''));
    169 }
    170
    171 try {
    172 	// workaround for IE, 因用 General type, 效能較差
    173 	var d = document.createElement('div'), s;
    174 	// alert('toString test: ' + element_pattern.test(get_object_type.call(d)));
    175
    176 	if(d.nodeType !== ELEMENT_NODE)
    177 		//	doesn't support W3C DOM?
    178 		throw 0;
    179
    180 	if (!(s = element_pattern.test(get_object_type.call(d)))) {
    181 		if (element_pattern.test('' + d))
    182 			// IE8-9
    183 			_.is_HTML_element = function(value) {
    184 				return element_pattern.test('' + value)
    185 						// for IE8. value 可能是 null!
    186 						|| typeof value === 'object' && value !== null && value.nodeType === ELEMENT_NODE// && value.tagName === "OBJECT"
    187 							&& "[object NamedNodeMap]" === '' + value.attributes;
    188 			};
    189 		else if (get_object_type.call(d) === '[object Object]')
    190 			// IE5-7, 這種判別方法有漏洞!
    191 			_.is_HTML_element = function(value) {
    192 				return '[object Object]' === get_object_type.call(value) && value !== null && typeof value.nodeType === 'number';
    193 			};
    194 		else
    195 			throw 1;
    196
    197 		//	General type
    198 		_.is_HTML_element_type = function(value, type) {
    199 			return _.is_HTML_element(value) && value.nodeType === type;
    200 		};
    201 		_.is_element_node = function(value) {
    202 			return _.is_HTML_element(value) && value.nodeType === ELEMENT_NODE;
    203 		};
    204 	}
    205
    206 } catch (e) {
    207 	// TODO: handle exception
    208 } finally {
    209 	d = null;
    210 }
    211
    212
    213
    214 /*	test if can use flash
    215
    216 	better use SWFObject:
    217 	http://code.google.com/p/swfobject/
    218
    219 	Browser detect:	http://www.quirksmode.org/js/detect.html
    220 var plugin=(window.navigator.mimeTypes && window.navigator.mimeTypes["application/x-shockwave-flash"]) ? window.navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;
    221 if ( plugin ) {
    222         plugin=parseInt(plugin.description.substring(plugin.description.indexOf(".")-1)) >= 3;
    223 }
    224 else if (window.navigator.userAgent && window.navigator.userAgent.indexOf("MSIE")>=0 && window.navigator.userAgent.indexOf("Windows")>=0) {
    225         document.write('<SCRIPT LANGUAGE=VBScript\> \n');
    226         document.write('on error resume next \n');
    227         document.write('plugin=( IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.6")))\n');
    228         document.write('<\/SCRIPT\> \n');
    229 }
    230 if ( plugin ) {
    231         document.write('<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"');
    232         document.write('  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ');
    233         document.write(' ID=flash5clickTAG WIDTH='+n_width+' HEIGHT='+n_height+'>');
    234         document.write(' <PARAM NAME=movie VALUE="'+ n_flashfile +'"><param name=wmode value=opaque><PARAM NAME=loop VALUE=true><PARAM NAME=quality VALUE=high>  ');
    235         document.write(' <EMBED src="'+ n_flashfile +'" loop=true wmode=opaque quality=high  ');
    236         document.write(' swLiveConnect=FALSE WIDTH='+n_width+' HEIGHT='+n_height+'');
    237         document.write(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">');
    238         document.write(' <\/EMBED>');
    239         document.write(' <\/OBJECT>');
    240 } else if (!(window.navigator.appName && window.navigator.appName.indexOf("Netscape")>=0 && window.navigator.appVersion.indexOf("2.")>=0)){
    241         document.write('<A HREF="'+ n_altURL +'" target="'+n_target+'"><IMG SRC="'+ n_altimg +'" WIDTH='+n_width+' HEIGHT='+n_height+' BORDER=0><\/A>');
    242 }
    243 */
    244
    245 //	copy from base.js
    246 //window.onerror=HandleError;
    247 function HandleError(message, url, line) {
    248 	// if(window.confirm())_DO_CONTINUE_
    249 	if (window.navigator.appName == "Microsoft Internet Explorer")
    250 		return !window.confirm(url + '\n\nJavaScript Error: ' + line
    251 				+ '\n' + message + '\n\nSee more details?');
    252 	else if (window.navigator.appName == "Netscape")
    253 		// document.location.href="javascript:";
    254 		window.navigate('javascript:');
    255
    256 	//return message;	'Warning: function HandleError does not always return a value' in some Firebird with	user_pref("javascript.options.strict", true);	@ prefs.js
    257 }
    258
    259 //window.onresize=OnResize;	//	預防(舊版)NS resize時版面亂掉
    260 function OnResize() {
    261 	//	回上一頁	history.go(-1),history.back()/history.forward()	this.location.replace(document.referrer)
    262 	//	Opera's document.referrer returns only null if referrer logging is disabled
    263 	//location.replace(),location.reload()
    264 	history.go(0);
    265 }
    266
    267 /*
    268 IE only!!
    269 	http://blog.livedoor.jp/dankogai/archives/50952477.html	DOM時代のdocument.write()
    270
    271 if (typeof document == 'object')
    272 	write = document.write;
    273 */
    274
    275 /*
    276 http://blog.taragana.com/index.php/archive/how-to-enable-windowstatus-in-firefox/
    277 window.status在firefox下默認是不能修改的。
    278 可以通過工具->選項->網頁特性->啟用javascript->高級->把修改狀態欄文本打上勾就好了。
    279
    280 Open about:config in browser and search for dom.disable_window_status_change. Change it to false.
    281 Additionally in Firefox v1.0, this can be changed via "Tools → Options → Web Features → Enable JavaScript / Advanced → Allow scripts to change status bar text"
    282 In Firefox v1.5, this can be changed via "Tools → Options → Content → Enable JavaScript / Advanced → Allow scripts to change status bar text"
    283 via MozillaZine; learnt the hard way.
    284 */
    285 function RollStatus(m,v,from,RollStatusL){//message,速度velocity,from where,unit length(基本上後兩者勿設定)
    286  var s='    ';//間隔以s
    287  if(!RollStatusL)RollStatusL=m.length,m+=s+m;if(!from||from>=RollStatusL+s.length)from=0;
    288  if(!m)if(window.status)RollStatus(window.status,v);else return;else if(m.slice(from)!=window.status&&m.length>L)return;
    289  var L=99,V=v||999;//L:least length
    290  while(m.length<L)m+=s+m;
    291  window.status=m.slice(++from);
    292  RollStatusS=window.setTimeout('RollStatus("'+m+'",'+V+','+from+','+RollStatusL+');',V);
    293  //RollStatusS=window.setInterval('RollStatus("'+m+'",'+V+','+from+')',V)
    294 }
    295
    296 //	↑copy from base.js
    297
    298
    299 /*	預防hack：禁止鍵盤keyboard&滑鼠mouse輸入,可以再加上一層div於最上方以防止copy
    300 	下面一行調到檔案頭
    301 var disabledKM=0;
    302 */
    303 //disableKM[generateCode.dLK]='disabledKM';
    304 function disableKM(s,m){	//	s=1:回復,s=2:使螢幕亦無法捲動(對NS無效),m:message,輸入時發出警告
    305  /*
    306  window.onerror=function(){return ture;};
    307  //	定義亦可用 function document.onmousedown(){..}
    308  document.onmousedown=document.oncontextmenu=document.onselectstart=document.ondragstart=function(e){return false;};
    309  //	印刷を禁止して
    310  window.onbeforeprint=function(){for(i=0;i<document.all.length;i++){if(document.all[i].style.visibility!="hidden"){document.all[i].style.visibility="hidden";document.all[i].id="elmid";}}};
    311  window.onafterprint=function(){for(i=0;i<document.all.length;i++){if(document.all[i].id=="elmid"){document.all[i].style.visibility="";}}};
    312  */
    313  if(!document.body)return;
    314  if(typeof s=='undefined')s=1;
    315  if(typeof disabledKM=='undefined')disabledKM=0;
    316
    317  if(!s){
    318   if(disabledKM){
    319    ondragstart=document.body.Oondragstart||null,
    320    oncontextmenu=document.body.Ooncontextmenu||null,
    321    onselectstart=document.body.Oonselectstart||null;
    322    with(window.document.body)
    323     if(disabledKM==2)style.overflow=typeof document.body.Ooverflow=='string'?Ooverflow:'auto';
    324    onmousedown=window.Oonmousedown||null,
    325    onkeydown=window.Oonkeydown||null;
    326    onmousedown=document.Oonmousedown||null,
    327    onkeydown=document.Oonkeydown||null;
    328   }
    329   disabledKM=0;
    330   return;
    331  }
    332
    333 if(disabledKM){with(document.body)	//	已lock時不執行多餘的動作與覆蓋舊資訊
    334  if(s==2)style.overflow='hidden';
    335  else if(typeof document.body.Ooverflow=='string')style.overflow=Ooverflow;
    336 }else{
    337 //	<body oncontextmenu="return false" ondragstart="return false" onselectstart="return false">
    338  with(document.body){	//	預防hack
    339   //leftMargin=topMargin=rightMargin=bottomMargin=0;	//	使body填滿視窗
    340   document.body.Ooverflow=style.overflow;
    341   if(s==2)style.overflow='hidden';	//	使螢幕亦無法捲動
    342   if(typeof onselectstart!='undefined')document.body.Oonselectstart=onselectstart;
    343   if(typeof oncontextmenu!='undefined')document.body.Ooncontextmenu=oncontextmenu;
    344   if(typeof ondragstart!='undefined')document.body.Oondragstart=ondragstart;
    345   ondragstart=oncontextmenu=onselectstart=
    346 	//new Function("return false;");
    347 	function(){return false;};
    348  }
    349  //	不要在 document 对象中设置 expando 属性，在 window 对象上设置 expando 属性。
    350  with(window){
    351   if(typeof onmousedown!='undefined')document.Oonmousedown=onmousedown;
    352   if(typeof onkeydown!='undefined')document.Oonkeydown=onkeydown;
    353  }
    354  with(window.document){
    355   //ndblclick=
    356   if(typeof onmousedown!='undefined')document.Oonmousedown=onmousedown;
    357   if(typeof onkeydown!='undefined')document.Oonkeydown=onkeydown;
    358  }
    359 }
    360  window.onmousedown=window.onkeydown=document.onmousedown=document.onkeydown=document.onContextMenu
    361 	=new Function('e',
    362 			'if(window.navigator.appName=="Microsoft Internet Explorer"&&event.button!=1||window.navigator.appName=="Netscape"&&e.which!=1){'
    363 			+(m?'alert('+dQuote(m)+');':'')+'return false;}');
    364 /*
    365 			'if(window.navigator.appName=="Microsoft Internet Explorer"\
    366 			&&event.button!=1||window.navigator.appName=="Netscape"&&e.which!=1){'+(m?'alert('+dQuote(m)+');':'')+'return false;}');
    367 */
    368
    369  //	window.captureEvents(Event.MOUSEUP|Event.MOUSEDOWN);
    370  //	window.onmousedown=function(e){if(e.which==1){window.captureEvents(Event.MOUSEMOVE);window.onmousemove=rf;}};
    371  //	window.onmouseup=function(e){if(e.which==1){window.releaseEvents(Event.MOUSEMOVE);window.onmousemove=null;}};
    372  //	Navigator 4.0x
    373  //	http://topic.csdn.net/t/20020125/13/498661.html
    374  if(!disabledKM && window.Event && window.captureEvents)
    375 	window.captureEvents(Event.MOUSEDOWN),
    376 	window.captureEvents(Event.KEYDOWN);
    377
    378  disabledKM=s;
    379 };
    380
    381
    382 CeL.interact.DOM
    383 .
    384 /**
    385  * toggle/swap display and visibility.
    386  * display:none or visibility:hidden.
    387  * TODO: computed style
    388  * @param element	HTML element
    389  * @param	{String|Number} type	show or hidden or set the status type:
    390  * 			{Number} type: 0: hidden(→none), 1: show(→block), 2||undefined: switch, others: get status only with no change
    391  * 			{String} type: set CSS: display type: none, '', block, inline, list-item. 其他恐造成 error?
    392  * @return	display status
    393  * @since	2010/4/1 10:24:43 rewrite
    394  * @see
    395  * http://www.w3schools.com/CSS/pr_class_visibility.asp
    396  * http://www.w3schools.com/css/pr_class_display.asp
    397  * http://www.javaeye.com/topic/140784
    398  * 	通過element.style對象只能取得內聯的樣式，也就是說只能取得html標籤裡寫的屬性。
    399  * @requires	[_.get_element],[_.get_style]
    400  * @memberOf	CeL.interact.DOM
    401  */
    402 toggle_display = function(element, type){
    403 	// showObj(div);
    404 	if (typeof element === 'string')
    405 		element = typeof _.get_element === 'function' ? _.get_element(element)
    406 			: document.getElementById(element);
    407
    408 	if (!element)
    409 		return;
    410
    411 	// Opera 7.5 意外的沒有 tagName (-_-) 而 Firefox 也可能沒有此 property
    412 	var tagName = ('' + element.tagName).toLowerCase(), style = element.style,
    413 		v_value = {'visible':1, 'hidden': 2, 'collapse': 3};
    414
    415 	if (typeof type === 'undefined' || type == 2)
    416 		type = style ?
    417 				(_.get_style ? _.get_style(element, 'display') :
    418 					//	style.display === '' 時預設為顯示
    419 					style.display) === 'none'
    420 			: element.visibility !== 'visible';
    421
    422 	if (typeof type === 'boolean')
    423 		type = type ? 1 : 0;
    424
    425 	if (!isNaN(type))
    426 		type = type == 0 ? style ? 'none' : tagName === 'tr' ? 'collapse' : 'hidden'
    427 			: type == 1 ? style ? (tagName in {'div':1, 'iframe':1}) ? 'block' : 'inline' : 'visible'
    428 			: null;
    429
    430 	//	test .innerHTML
    431
    432 	//library_namespace.debug('set display style to [' + type + ']');
    433 	if (style)
    434 		style[type in v_value? 'visibility' : 'display'] = type;
    435 	else if(type in v_value)// &&!(tagName in {'iframe':1,'input':1})
    436 		element.visibility = type;
    437 	else return;
    438
    439 	return type;
    440 };
    441 //simpleWrite('a.txt',reduceCode([f,toggle,setObjValue]));
    442 //for(var i in style)tt+=i+'='+document.getElementById("others").style[i]+"<br/>";document.write(tt);
    443
    444
    445
    446 CeL.interact.DOM
    447 .
    448 /*	http://blog.stevenlevithan.com/archives/faster-than-innerhtml
    449 You can use the above as el = replace_HTML(el, newHtml) instead of el.innerHTML = newHtml.
    450
    451 .innerHTML=,document.createElement(→XML_node()
    452 .innerHTML='' → remove_all_child
    453
    454
    455 http://forum.moztw.org/viewtopic.php?t=17984&postdays=0&postorder=asc&start=15
    456 adoptNode() 會把現有的節點拿去用，ownerDocument 會被變更，被 adopt 的節點會從原來的 document 消失。
    457 importNode() 比較像是 cloneNode() 加上變更 ownerDocument。
    458 以前因為 Gecko 沒有太嚴格，所以可以用 Ajax 取回一個 XML 文件並直接透過 responseXML 把裡面的節點當 HTML 節點一樣的插入現有的網頁。
    459 */
    460 /**
    461  * replace HTML
    462  * @param o
    463  * @param html
    464  * @return
    465  * @memberOf	CeL.interact.DOM
    466  */
    467 replace_HTML = function(o, html){
    468 	if (typeof o === 'string')
    469 		o = document.getElementById(o);
    470 	if (!o || typeof o !== 'object')
    471 		return;
    472 	try{
    473 		/*@cc_on	// Pure innerHTML is slightly faster in IE
    474 		 o.innerHTML=html||'';
    475 		 return o;
    476 		@*/
    477 		var n = o.cloneNode(false);
    478 		n.innerHTML = html || '';
    479 		o.parentNode.replaceChild(n, o);
    480 	}catch (e) {
    481 		library_namespace.err(e);
    482 	}
    483 	// Since we just removed the old element from the DOM, return a reference to the new element, which can be used to restore variable references.
    484 	return n;
    485 };
    486
    487 /*
    488 使用.firstChild或.lastChild須注意此node可能是text node，不能appendChild。須以.nodeType判別。
    489
    490 http://msdn2.microsoft.com/zh-tw/library/system.xml.xmlnode.removechild(VS.80).aspx
    491 繼承者注意事項 在衍生類別中覆寫 RemoveChild 時，為了要正確引發事件，您必須呼叫基底類別的 RemoveChild 方法。
    492
    493 removeAllChild[generateCode.dLK]='replace_HTML';
    494 function removeAllChild(o){
    495  //return removeNode(o,1);
    496
    497  //	http://blog.stevenlevithan.com/archives/faster-than-innerhtml
    498  if(typeof o=='string')o=document.getElementById(o);
    499  if(!o||typeof o!='object')return;
    500  o.parentNode.replaceChild(o.cloneNode(false),o);
    501  return o;
    502 }
    503
    504 http://www.webreference.com/js/column43/replace.html
    505 The replaceNode method is much more intuitive than the removeNode method. While the removeNode method just removes the specified element and makes its descendents children of their grandfather, the replaceNode method deletes the whole subtree that is rooted at the specified element, and substitutes it with a new element.
    506 node_want_to_replace.removeNode(new_node)
    507 */
    508 CeL.interact.DOM
    509 .
    510 /**
    511  * 移除 node.
    512  * TODO:
    513  * also remove event handlers
    514  * @param o
    515  * @param tag	tag===1: only child, undefined: remove only self, others: only <tag> child
    516  * @return
    517  * @memberOf	CeL.interact.DOM
    518  */
    519 remove_node = function remove_node(o, tag) {
    520 	var _f = remove_node, i;
    521 	if (typeof o === 'string')
    522 		o = document.getElementById(o);
    523 	if (!o || typeof o !== 'object')
    524 		return;
    525
    526 	// remove child
    527 	if (tag) {
    528 		if (typeof tag === 'string')
    529 			tag = tag.toLowerCase();
    530
    531 		//	safer: if you have any asynchronous events going. But node.hasChildNodes() will always do an evaluation.
    532 		//while(o.hasChildNodes()&&(i=o.firstChild))o.removeChild(i);
    533
    534 		// don't use for()
    535 		// http://weblogs.macromedia.com/mesh/archives/2006/01/removing_html_e.html
    536 		//	TODO: 直接用 replaceNode 就不用 recursion
    537 		i = o.childNodes.length;
    538 		while (i--)
    539 			if (tag === 1 || tag == o.childNodes[i].tagName.toLowerCase())
    540 				// _f(o.childNodes[i],tag), // TODO: 會有問題
    541 				o.removeChild(o.childNodes[i]);
    542 	}
    543
    544 	// remove self
    545 	//	測試 o.parentNode: 預防輸入的o為create出來的
    546 	return tag || !(i = o.parentNode) ? o : i.removeChild(o);
    547 };
    548
    549 CeL.interact.DOM
    550 .
    551 remove_all_child = _.replace_HTML;
    552
    553
    554
    555
    556
    557 CeL.interact.DOM
    558 .
    559 /**
    560  * set/get/remove attribute of a element<br/>
    561  * in IE: setAttribute does not work when used with the style attribute (or with event handlers, for that matter).
    562  * @param _e	element
    563  * @param propertyO	attributes object (array if you just want to get)
    564  * @return
    565  * @requires	split_String_to_Object
    566  * @see
    567  * setAttribute,getAttribute,removeAttribute
    568  * http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html
    569  * @since	2006/12/10 21:25 分離 separate from XML_node()
    570  * @memberOf	CeL.interact.DOM
    571  */
    572 set_attribute = function(_e, propertyO, ns) {
    573 	if (typeof _e === 'string')
    574 		_e = typeof _.get_element === 'function' ? _.get_element(_e)
    575 				: document.getElementById(_e);
    576 		if (!_e || !propertyO/* ||_e.nodeType==3/* TEXT_NODE */)
    577 			return;
    578
    579  var _l,_m,_g,
    580 	//	Namespaces:SVG,MathML,XHTML,XLink
    581  _N=_.new_node.ns;
    582  if (typeof propertyO == 'string')
    583 	 propertyO = /[=:]/.test(propertyO) ? split_String_to_Object(propertyO)
    584 			 : propertyO.split(',');
    585 	 if (propertyO instanceof Array)
    586 		 _g = propertyO.length == 1 ? propertyO[0] : 1,
    587 				 propertyO = split_String_to_Object(propertyO.join(','));
    588
    589 		 for (_l in propertyO) {
    590 			 if (_l == 'class' && !propertyO['className'])
    591 				 propertyO[_l = 'className'] = propertyO['class'];
    592 			 if (_g || (_l in propertyO) && propertyO[_l] != null)
    593    if(_l=='className'||typeof propertyO[_l]=='function')if(_g)propertyO[_l]=_e[_l];else _e[_l]=propertyO[_l];//_l=='id'||
    594 	/*
    595 		XML 中id不能以setAttribute設定。
    596 		class不能以setAttribute設定@IE。
    597 		http://www.quirksmode.org/bugreports/archives/2005/03/setAttribute_does_not_work_in_IE_when_used_with_th.html
    598 		IE ignores the "class" setting, and Mozilla will have both a "class" and "className" attribute defined
    599 	*/
    600    else if (_e.setAttributeNS
    601 		   && (_m = _l.match(/^(.+):([^:]+)$/))) {
    602 	   _m = _m[1];
    603 	   if (_m.indexOf('://') == -1 && _N[_m.toLowerCase()])
    604 		   _m = 'http://www.w3.org/' + _N[_m.toLowerCase()];
    605 	   if (_g)
    606 		   propertyO[_l] = _e.getAttributeNS(_m, _l);
    607 	   else
    608 		   _e.setAttributeNS(_m, _l, propertyO[_l]);// try{_e.setAttributeNS(_m,_l,propertyO[_l]);}catch(e){alert('set_attribute:
    609 	   // Error!');}
    610    } else if (_g)
    611 	   propertyO[_l] = _e.getAttribute(_l);
    612    else
    613 	   _e.setAttribute(_l, propertyO[_l]);// _e.setAttributeNS?_e.setAttributeNS(null,_l,propertyO[_l]):_e.setAttribute(_l,propertyO[_l]);
    614  }
    615
    616  return typeof _g == 'string' ? propertyO[_g] : propertyO;
    617 };
    618
    619
    620 CeL.interact.DOM
    621 .
    622 /**
    623  * append children node to specified element
    624  * @param node	node / node id
    625  * @param child_list	children node array
    626  * @return
    627  * @since	2007/1/20 14:12
    628  * @memberOf	CeL.interact.DOM
    629  */
    630 add_node = function add_node(node, child_list) {
    631 	var _s = add_node;
    632 	if (typeof node === 'string')
    633 		node = typeof _.get_element === 'function' ? _.get_element(node)
    634 				: document.getElementById(node);
    635
    636 	if (node && arguments.length > 2) {
    637 		for ( var _j = 1, l = arguments.length; _j < l; _j++)
    638 			_s(node, arguments[_j]);
    639 		return;
    640 	}
    641
    642 	if (!node || !child_list
    643 			// || node.nodeType == 3/* TEXT_NODE */
    644 	)
    645 		return;
    646
    647 	//	預防 RegExp 等，需要 toString()
    648 	if (child_list instanceof RegExp)
    649 		child_list = '';
    650
    651 	if (typeof child_list === 'object') {
    652 		if (child_list)
    653 			if (child_list instanceof Array
    654 					// && child_list.length
    655 			)
    656 				for ( var _j = 0, l = child_list.length; _j < l; _j++)
    657 					_s(node, child_list[_j]);
    658 			else
    659 				node.appendChild(child_list);
    660 		return;
    661 	}
    662 	if (typeof child_list === 'number' && !isNaN(child_list))
    663 		// child_list=child_list.toString();
    664 		child_list += '';
    665 	if (typeof child_list === 'string') {
    666 		var tag_name = node.tagName.toLowerCase();
    667 		if (tag_name === 'textarea' || tag_name === 'select' || tag_name === 'option'
    668 			|| (tag_name === 'input' && node.type === 'text'))
    669 			node.value = child_list;
    670 		else if (tag_name === 'option') {
    671 			if (!node.value)
    672 				node.value = child_list;
    673 			node.innerHTML = child_list;
    674 		} else if (child_list.indexOf('<') != -1)
    675 			//	may cause error: -2146827687 未知的執行階段錯誤 e.g., XML_node('a',0,0,[XML_node('a'),'<br/>']);
    676 			//try{
    677 				node.innerHTML += child_list;
    678 			//}catch(e){node.appendChild(XML_node('span',0,0,child_list));}
    679
    680 		else
    681 			//try{
    682 				node.appendChild(document.createTextNode(child_list));
    683 			//}catch(e){alert(e.description);}
    684
    685 		// else alert('add_node: Error insert contents:\n['+child_list+']');
    686 	}
    687 };
    688
    689
    690 /*
    691
    692 var alias={
    693 	//	'child' || 'c' || '$' || '0' || ..
    694 	$:'childNode',
    695 	//	class: 'className' || 'c' ..
    696 	c:'className'
    697 	s:'style'
    698 };
    699
    700 輸入 ( [{tag1:{attb:attb_val,child:[inner objects]}}, {tag2:{}}, 'br'], insertBeforeO)
    701 e.g.,
    702 ([
    703 	{
    704 		p:[span:'>>test<<'],
    705 		id:'a',
    706 		c:'cls',
    707 		s:{color:'#123'}
    708 	},
    709 	//	width:12 === width:'12px'
    710 	{
    711 		span:['<<test2>>','text'],
    712 		s:{color:'',width:12}
    713 	},
    714 	'<<test3>>',
    715 	{'hr':0},
    716 	{'br':0},
    717 	{
    718 		$:tag_name,
    719 		tag_name:[]
    720 	},
    721 	{
    722 		tag_ns:0,
    723 		ns:'http://~'
    724 	}
    725 ], insertSetting)
    726
    727 insertSetting:
    728 	(null)		just create & return the node
    729 	以下：===0 則設成 document.body
    730 	parent/id		appendChild
    731 	[refO,0-4]	0:appendChild (add as lastChild), 1: add as firstChild, 2: add as nextSibling, 3: add as priviusSibling, 4: add as parent
    732
    733
    734 */
    735 //[{tag1:{attb:attb_val,child:[inner objects]}}, {tag2:{}}, 'br'];
    736
    737
    738
    739 CeL.interact.DOM
    740 .
    741 /**
    742  * 創建新的 DOM 節點(node)。
    743  * createNode() 的功能補充加強版。
    744  * TODO: 分割功能(set_attrib, add_child, ..), 簡化
    745  * @param	{Object|Array} nodes	node structure
    746  * @param	{String|Array|HTMLElement} [layer]	where to layer this node. e.g., parent node
    747  * @return	{HTMLElement}	new node created
    748  * @since	2010/6/21 13:45:02
    749  */
    750 new_node = function(nodes, layer) {
    751 	var _s = _.new_node, node, for_each,
    752 	// parent: parent node of layer or layer.firstChild
    753 	parent,
    754 	children,
    755 	handle = _s.handle;
    756
    757 	if (!is_DOM('document')
    758 		|| !document.createElement
    759 		//&& !document.createElementNS
    760 		) {
    761 		library_namespace.warn('new_node: DOM error? Cannot create node [' + nodes + '].');
    762 		return;
    763 	}
    764
    765 	if (typeof nodes === 'number')
    766 		//.toString();
    767 		nodes += '';
    768
    769 	if (library_namespace.is_Object(nodes)) {
    770 		var tag = nodes.$, n = 'className', ns, s, ignore = {
    771 			// tag
    772 			$ : null,
    773 			// attrib
    774 			A : null
    775 /*
    776 			// namespace
    777 			NS : null,
    778 			// class
    779 			C : null,
    780 			// style
    781 			S : null
    782 */
    783 		};
    784
    785 		if (typeof tag === 'undefined')
    786 			for (node in nodes)
    787 				if(!(node in ignore)){
    788 					tag = node;
    789 					break;
    790 				}
    791 		else if (tag === 0) {
    792 			//	0: just set attributes
    793 			if (!_.is_element_node(layer)) {
    794 				library_namespace.warn('new_node: There is no tag and the layer is NOT a HTML Element!');
    795 				return;
    796 			}
    797 			tag = layer;
    798 		}else if (typeof tag !== 'undefined')
    799 			node = tag;
    800
    801 		//	set/create node
    802 		if (_.is_HTML_element(tag))
    803 			node = tag;
    804
    805 		else if (typeof tag !== 'string'){
    806 			library_namespace.err('new_node: Error create tag: ['+(typeof tag)+'][' + tag + ']');
    807 			return;
    808
    809 		} else {
    810 			if ('NS' in nodes)
    811 				ignore.NS = null,
    812 				ns = nodes.NS;
    813 			else if (s = tag.match(/^(.+):([^:]+)$/))
    814 				tag = s[2], ns = s[1];
    815
    816 			try {
    817 				if (ns && document.createElementNS) {
    818 					if (ns in (s = _s.ns))
    819 						ns = 'http://www.w3.org/' + s[ns];
    820 					node = document.createElementNS(ns, tag);
    821 				} else
    822 					node = tag ? document.createElement(ns ? ns + ':' + tag : tag)
    823 							//: document.createTextNode();
    824 							//	由後面判定。
    825 							: nodes[tag];
    826 			} catch (_e) {
    827 				library_namespace.err('new_node: Error create tag: [' + tag + ']');
    828 				node = null;
    829 				return;
    830 			}
    831 		}
    832
    833 		if (_.is_element_node(node)) {
    834 			s = node.setAttributeNS ? function(n, v) {
    835 				if (library_namespace.is_Function(v)) {
    836 					node[n] = v;
    837 					//	TODO: _.add_listener();
    838 					return;
    839 				}
    840 				var _n = n.match(/^(.+):([^:]+)$/);
    841 				if (_n)
    842 					n = _n[2], _n = _n[1];
    843 				if (_n)
    844 					node.setAttributeNS(
    845 							_n in _s.ns ? 'http://www.w3.org/'
    846 									+ _s.ns[_n] : ns, n, v);
    847 				else
    848 					node.setAttribute(n, v);
    849 			} : function(n, v) {
    850 				if (library_namespace.is_Function(v))
    851 					node[n] = v;
    852 				else
    853 					node.setAttribute(n, v);
    854 			};
    855
    856 			//	對常用的特別處理
    857 			// class name
    858 			/*
    859 				XML 中id不能以setAttribute設定。
    860 				class不能以setAttribute設定@IE。
    861 				http://www.quirksmode.org/bugreports/archives/2005/03/setAttribute_does_not_work_in_IE_when_used_with_th.html
    862 				IE ignores the "class" setting, and Mozilla will have both a "class" and "className" attribute defined
    863 			 */
    864 			if ((n in nodes) || ((n = 'class') in nodes) || ((n = 'C') in nodes))
    865 				ignore[n] = null,
    866 				node.className = nodes[n];
    867
    868 			// IE 需要先 appendChild 才能操作 style，moz不用..??
    869 			//	http://www.peterbe.com/plog/setAttribute-style-IE
    870 			//	或需要將 font-size -> fontSize 之類?
    871 			// IE6 (no firefox or IE7~) 可設定:
    872 			//	oNewDiv.style.setAttribute('border', '1px solid #000');
    873 			//	oNewDiv.style.setAttribute('backgroundColor', '#fff');
    874 			if (((n = 'style') in nodes) || ((n = 'S') in nodes)) {
    875 				ignore[n] = null;
    876 				n = nodes[n];
    877 				var i, style = node.style;
    878 				if (typeof n === 'string')
    879 					style.cssText = n;
    880 				else if (library_namespace.is_Object(n))
    881 					for (i in n)
    882 						// is_IE?"styleFloat":"cssFloat"
    883 						style[i === 'float' ? 'cssFloat' in style ? 'cssFloat' : 'styleFloat' : i] = n[i];
    884 				else
    885 					library_namespace.warn('new_node: Error set style: [' + styleO + ']');
    886 			}
    887
    888 			// children nodes
    889 			ignore[tag] = null;
    890 			children = nodes[tag];
    891
    892 			//	自動作 list 的轉換
    893 			if (tag in {
    894 						ol : 1,
    895 						ul : 1
    896 					} && library_namespace.is_Array(children))
    897 			{
    898 				var i = 0, o = [], l = children.length, t, c, change = false;
    899 				for (; i < l; i++)
    900 					if (c = children[i]) {
    901 						t = typeof c === 'string'
    902 							|| typeof c === 'number';
    903 						if (!t && library_namespace.is_Object(t)) {
    904 							t = c.$;
    905 							if (!t)
    906 								for (t in c)
    907 									break;
    908 							t = t.toLowerCase() !== 'li';
    909 						}
    910
    911 						if(t)
    912 							change = true;
    913 						o.push(t ? {
    914 							li : c
    915 						} : c);
    916 					}
    917
    918 				// 盡量別動到原來的
    919 				if (change)
    920 					children = o;
    921
    922 			}else if(tag === 'select' && library_namespace.is_Object(children)){
    923 				var i;
    924 				for (i in children)
    925 					break;
    926
    927 				if (i !== 'option') {
    928 					var o = [];
    929 					for (i in children)
    930 						o.push( {
    931 							option : children[i],
    932 							value : i
    933 						});
    934
    935 					// 盡量別動到原來的
    936 					children = o;
    937 				}
    938 			}
    939
    940
    941 			// attributes
    942 			if('A' in nodes){
    943 				var a = nodes.A;
    944 				if (typeof a === 'string')
    945 					a = split_String_to_Object(a);
    946
    947 				for (n in a)
    948 					s(n, a[n]);
    949 			}
    950
    951 			for (n in nodes)
    952 				if (!(n in ignore)){
    953 					//library_namespace.debug('new_node: set attribute ['+n+'] = ['+nodes[n]+']'),
    954 					s(n, nodes[n]);
    955 					//library_namespace.debug('new_node: get attribute ['+n+'] = ['+node.getAttribute(n)+']');
    956 				}
    957 		} else if(tag && !_.is_HTML_element(node))
    958 			show_node(node),
    959 			library_namespace.warn('new_node: node is not a HTML Element!');
    960
    961 	} else if (typeof nodes !== 'string' && !library_namespace.is_Array(nodes)
    962 			&& isNaN(nodes.nodeType)) {
    963 		//	for Safari: library_namespace.is_Array(nodes)
    964 		if(nodes)
    965 			library_namespace.warn('new_node: Unknown nodes [' + nodes + ']');
    966
    967 		node = null;
    968 		return;
    969 	} else
    970 		node = nodes;
    971
    972
    973 	// layer 處理: 插入document中。
    974 	if (typeof layer !== 'undefined' && layer !== null) {
    975 		// 正規化 layer
    976 		// for_each: type→deal function
    977 		if (library_namespace.is_Function(layer))
    978 			for_each = layer;
    979 		else {
    980 			if (library_namespace.is_Array(layer))
    981 				for_each = layer[1], layer = layer[0];
    982
    983 			if (layer === 0)
    984 				layer = document.body;
    985 			else if (typeof layer === 'string')
    986 				layer = _.get_element(layer);
    987 			//	[object HTMLLIElement]
    988 			if (!_.is_element_node(layer))
    989 				//library_namespace.warn('is_element_node: ' + _.is_element_node),
    990 				show_node(layer),
    991 				library_namespace.warn('new_node: layer is not a HTML Element!');
    992
    993 			if (for_each == 1 && (parent = layer.firstChild))
    994 				// add as firstChild of layer
    995 				for_each = handle[1];
    996
    997 			else if (for_each > 1 && for_each < 5) {
    998 				if (parent = layer.parentNode) {
    999 					if (for_each == 2)
    1000 						// add as nextSibling of layer
    1001 						for_each = handle[2];
    1002 					else if (for_each == 3)
    1003 						// add as priviusSibling of layer
    1004 						for_each = handle[3];
    1005 					else
    1006 						// if (f == 4)
    1007 						// add as parent of layer
    1008 						for_each = handle[4];
    1009 				} else
    1010 					// 輸入的 layer 為create出來的?
    1011 					library_namespace.warn('new_node: No parent node found!');
    1012
    1013 			} else if (_.is_element_node(layer)){
    1014 				//	若輸入 [id, null] 則先清空，相當於 replace
    1015 				if (for_each === null)
    1016 					layer = _.remove_all_child(layer);
    1017 				// appendChild (add as lastChild)
    1018 				for_each = handle[0];
    1019 			}
    1020 		}
    1021
    1022 	}
    1023
    1024 	if (!library_namespace.is_Function(for_each))
    1025 		for_each = false;
    1026
    1027 	if (library_namespace.is_Array(node)) {
    1028 		node = [];
    1029 		//	不宜個個重新呼叫是為了效能
    1030 		for ( var i = 0, l = nodes.length, n, _l = layer, _p = parent; i < l; i++) {
    1031 			node.push(n = _s(nodes[i], for_each && function(n) {
    1032 					for_each(n, _l, _p);
    1033 				} || null));
    1034 			/*
    1035 			node.push(n = _s(nodes[i], for_each));
    1036 			if (for_each)
    1037 				try {
    1038 					for_each(n, layer, parent);
    1039 				} catch (e) {
    1040 					library_namespace.err(e);
    1041 					library_namespace.err('new_node: handle function execution error for node Array['+i+'/'+l+']!<br/>' + for_each);
    1042 				}
    1043 			*/
    1044 		}
    1045
    1046 	} else{
    1047 		if (typeof node === 'string' && for_each !== handle[0])
    1048 			node = document.createTextNode(nodes);
    1049
    1050 		if (for_each)
    1051 			try {
    1052 				for_each(node, layer, parent);
    1053 			} catch (e) {
    1054 				library_namespace.err(e);
    1055 				library_namespace.err('new_node: handle function execution error!<br/>' + for_each);
    1056 			}
    1057
    1058 		//	設定 childNodes
    1059 		//	先插入document而後設定childNodes是因為IE有Cross-Page Leaks.
    1060 		//	http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
    1061 		//	http://www-128.ibm.com/developerworks/tw/library/x-matters41.html
    1062 		//	Try to use createDocumentFragment()
    1063 		//	http://wiki.forum.nokia.com/index.php/JavaScript_Performance_Best_Practices
    1064 		if (children !== null && typeof children !== 'undefined')
    1065 			_s(children, node);
    1066 	}
    1067
    1068
    1069 	//	This helps to fix the memory leak issue.
    1070 	//	http://www.hedgerwow.com/360/dhtml/ie6_memory_leak_fix/
    1071 	//	http://jacky.seezone.net/2008/09/05/2114/
    1072 	try {
    1073 		return typeof node === 'string' ? document.createTextNode(node) : node;
    1074 	} finally {
    1075 		node = null;
    1076 	}
    1077 };
    1078
    1079 _.new_node.handle = [
    1080 	function(n, l) {
    1081 		var is_e = _.is_element_node(l), t = is_e ? l.tagName.toLowerCase() : null;
    1082 		if (typeof n === 'number')
    1083 			n += '';
    1084
    1085 		if (t in {
    1086 				//	no <select>!
    1087 				textarea : 1,
    1088 				input : 1,
    1089 				text : 1
    1090 			})
    1091 			l.value = (l.value || '') + (is_e ? n.innerHTML : n);
    1092
    1093 		else {
    1094 			if (typeof n === 'string' && n.indexOf('<') === -1){
    1095 				if (t === 'option' && !l.value)
    1096 					l.value = n;
    1097 				n = document.createTextNode(n);
    1098 			}
    1099
    1100 			if (typeof n === 'string')
    1101 				// this may throw error: -2146827687 未知的執行階段錯誤
    1102 				l.innerHTML += n;
    1103 			else{
    1104 				t = l.innerHTML;
    1105 				l.appendChild(n);
    1106 				if (t === l.innerHTML)
    1107 					;//library_namespace.warn('new_node.handle[0]: The addition does not change the layer!');
    1108 			}
    1109 		}
    1110 		n = null;
    1111 	}, function(n, l, p) {
    1112 		l.insertBefore(n, p);
    1113 	}, function(n, l, p) {
    1114 		//	將 node 插入作為 layer 之 nextSibling.
    1115 		//	p: parent node of layer
    1116 		//	TODO: 輸入多 node 時 cache next
    1117 		var next = l.nextSibling;
    1118 		if (next)
    1119 			p.insertBefore(n, next);
    1120 		else
    1121 			p.appendChild(n);
    1122 	}, function(n, l, p) {
    1123 		p.insertBefore(n, l);
    1124 	}, function(n, l, p) {
    1125 		n.appendChild(p.replaceChild(n, l));
    1126 	}
    1127 ];
    1128
    1129 // Namespaces: SVG,MathML,XHTML,XLink,..
    1130 _.new_node.ns = {
    1131 	svg : '2000/svg',
    1132 	mathml : '1998/Math/MathML',
    1133 	xhtml : '1999/xhtml',
    1134 	xlink : '1999/xlink',
    1135 	// 亦可用'1999/xhtml'
    1136 	html : 'TR/REC-html40',
    1137 	html4:'TR/REC-html40',
    1138 	html5:'TR/html5'
    1139 };
    1140
    1141
    1142
    1143 /*
    1144 XML_node('div','id:idName');	doesn't insert, just return the object
    1145 XML_node('div',{'id':null});	won't set id
    1146 XML_node('div',{'id':undefined});	won't set id
    1147
    1148 XML_node('div','id:idName',1);	insert at last of document
    1149 XML_node('div',{id:'idName'},refO);	insert before(prepend) obj refO: refO.parentNode.insertBefore(_newNode_,refO)
    1150 XML_node('div','id:idName',document.body);	insert at top of document
    1151 XML_node('div','id:idName',[parent]);	append as a child of obj parent: parent.appendChild(_newNode_)
    1152 XML_node('div','id:idName',[parent,0]);	append as a child of obj parent: parent.appendChild(_newNode_)
    1153 XML_node('div','id:idName',[parent,refNode]);	insert before refNode: parent.insertBefore(_newNode_,refNode)
    1154 XML_node('div','id:idName',[parent,refNode,1]);	insert after refNode: UNDO
    1155 XML_node('div','id:idName',[parent,1]);	insert as the first child of parent: parent.insertBefore(_newNode_,parent.firstChild)
    1156 XML_node('div','id:idName',[0,refNode]);	insert before refNode: document.body.insertBefore(_newNode_,refNode)
    1157 XML_node('div','id:idName',[0]);	append after all: document.body.appendChild(_newNode_,refNode)
    1158
    1159 XML_node('div','id:idName',0,'asas');	insert 'asas' as innerText
    1160 	new_node({div:'asas',id:'idName'},0);
    1161 XML_node('div','id:idName',0,'<a>sas</a>');	insert 'asas' as innerHTML
    1162 	new_node({div:{a:'sas'},id:'idName'},0);
    1163 XML_node('div','id:idName',0,obj);	insert obj as childNode
    1164 	new_node({div:obj,id:'idName'},0);
    1165 XML_node('div','id:idName',0,[o1,o2]);	insert o1,o2 as childNodes
    1166 	new_node({div:[o1,o2],id:'idName'},0);
    1167
    1168
    1169 有用到新建 HTML element 的函數執行完畢應該將所有變數，尤其是 object 重設；
    1170 這是因為 HTML element 的存在會使函數裡的 object 變數不能被釋放。
    1171 設成 null 是因為 null 不能設定 method，而 string, number 可以。
    1172
    1173 http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
    1174 為預防IE Cross-Page Leaks，
    1175 use:
    1176 XML_node(++, ++, [XML_node(.., .., [meta])]);
    1177 instead of:
    1178 XML_node(.., .., [meta], XML_node(++, ++));
    1179 P.S. 2007/11/11 似乎已修正？
    1180
    1181
    1182 buggy 瑕疵:
    1183 XML_node(0,0,[parent],'innerText');	return a textNode append as a child of obj parent
    1184
    1185 TODO:
    1186 XML 中 insertBefore(),appendChild()似乎無反應？	http://developer.mozilla.org/en/docs/SVG:Namespaces_Crash_Course
    1187 insertAfter
    1188
    1189 */
    1190 CeL.interact.DOM
    1191 .
    1192 /**
    1193  * create new HTML/XML <a href="https://developer.mozilla.org/en/DOM/node">node</a>(<a href="https://developer.mozilla.org/en/DOM/element">element</a>)
    1194  * @param tag	tag name
    1195  * @param propertyO	attributes object
    1196  * @param insertBeforeO	object that we wnat to insert before it
    1197  * @param innerObj	inner object(s)
    1198  * @param styleO	style object
    1199  * @return	node object created
    1200  * @requires	set_attribute,add_node
    1201  * @since	2006/9/6 20:29,11/12 22:13
    1202  * @memberOf	CeL.interact.DOM
    1203  */
    1204 XML_node = function(tag, propertyO, insertBeforeO, innerObj, styleO) {
    1205 	//	XML 中沒有document.body！
    1206 	//if(typeof document.body=='undefined')document.body=document.getElementsByTagName('body')[0];
    1207
    1208 	if (typeof document !== 'object'
    1209 			|| (!document.createElement && !document.createElementNS)
    1210 			|| !document.body) {
    1211 		library_namespace.warn('XML_node: Cannot create tag [' + tag + '].');
    1212 		return;
    1213 	}
    1214
    1215 	var _NS,
    1216 	//	Namespaces: SVG,MathML,XHTML,XLink
    1217 	_i = _.new_node.ns,
    1218 	//	use Namespaces or not
    1219 	//	buggy now.
    1220 	_DOM2 = document.createElementNS ? 1 : 0,
    1221 	//	Namespaces base
    1222 	_e = 'http://www.w3.org/';
    1223
    1224 	/*
    1225 	//	依styleO指定 Namespace
    1226 	if (typeof styleO === 'string') {
    1227 		if (styleO.indexOf('://') != -1)
    1228 			_NS = styleO, styleO = 0;
    1229 		else if (_i[styleO])
    1230 			_NS = _e + _i[styleO], styleO = 0;
    1231 	} else
    1232 		// buggy now.
    1233 		_DOM2 = 0;//_NS = styleO === null ? null : _e + _i['XHTML'];//undefined==null
    1234 	*/
    1235
    1236 	//	指定 Namespace
    1237 	if (tag)
    1238 		if (_NS = tag.match(/^(.+):([^:]+)$/)) {
    1239 			tag = _NS[2];
    1240 			_NS = _NS[1];
    1241 			if (_NS.indexOf('://') === -1 && (_i = _i[_NS.toLowerCase()]))
    1242 				_NS = _e + _i;
    1243 			// library_namespace.warn('XML_node: Add ['+tag+'] of\n'+_NS);
    1244 		}
    1245
    1246 	/*
    1247 		for MathML:
    1248 			IE: document.createElement('m:'+tag)
    1249 				(surely 'mml:', but 'm:' is default of MathPlayer, so now <html> works without the xmlns attribute)
    1250 			NS: document.createElementNS('http://www.w3.org/1998/Math/MathML', tag)
    1251 	*/
    1252 	try {
    1253 		_e = tag ? _DOM2 && _NS ? document.createElementNS(_NS, tag)
    1254 				: document.createElement(tag/* .replace(/[<>\/]/g,'') */)
    1255 				: document.createTextNode(innerObj || '');
    1256 	} catch (_e) {
    1257 		library_namespace.warn('XML_node: Error create tag:\n' + tag/* + '\n' + _e.description */);
    1258 		return;
    1259 	}
    1260 	if (tag)
    1261 		_.set_attribute(_e, propertyO);
    1262
    1263 	//	IE需要先appendChild才能操作style，moz不用..??
    1264 	if (tag && styleO && _e.style)
    1265 		if (typeof styleO === 'string')
    1266 			_e.style.cssText = styleO;
    1267 		else if (typeof styleO === 'object')
    1268 			for (_i in styleO)
    1269 				//	is_IE?"styleFloat":"cssFloat"
    1270 				_e.style[_i === 'float' ? 'cssFloat' in _e.style ? 'cssFloat' : 'styleFloat' : _i] = styleO[_i];
    1271 	//else library_namespace.warn('XML_node: Error set style:\n[' + styleO + ']');
    1272
    1273
    1274 	//	插入document中。先插入document而後設定childNodes是因為IE有Cross-Page Leaks
    1275 	//	http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
    1276 	//	http://www-128.ibm.com/developerworks/tw/library/x-matters41.html
    1277 	if (insertBeforeO) {
    1278 		var rO = undefined/* [][1] */, tO = function(_o) {
    1279 			return typeof _o == 'string' && (_i = document.getElementById(_o)) ? _i
    1280 					: _o;
    1281 		}, iO = tO(insertBeforeO);
    1282 		// Opera9 need .constructor===Array
    1283 		if (library_namespace.is_Array(iO) && iO.length)
    1284 			// 在disable CSS時可能會 Warning: reference to undefined property iO[1]
    1285 			// rO: referrer object,
    1286 			// 以此決定以appendChild()或insertBefore()的形式插入
    1287 			rO = iO.length > 1 && tO(iO[1]) || 0, iO = tO(iO[0]);
    1288
    1289 		//if(typeof iO !== 'object' && (iO = document.body, typeof rO === 'undefined')) rO = 0;
    1290 		if (typeof iO !== 'object') {
    1291 			iO = document.body;
    1292 			if (typeof rO === 'undefined')
    1293 				rO = 0;
    1294 		}
    1295
    1296 		if (typeof rO === 'undefined')
    1297 			iO = (rO = iO).parentNode;
    1298 		if (iO)
    1299 			// 預防輸入的rO為create出來的
    1300 			if (rO)
    1301 				try {
    1302 					//	.firstChild == .childNodes[0]
    1303 					iO.insertBefore(_e, rO === 1 ? iO.firstChild : rO);
    1304 				} catch (e) {
    1305 					library_namespace.warn('XML_node: ' + e.message + '\niO:'
    1306 							+ iO + '\nrO:' + rO);
    1307 				}
    1308 				else
    1309 					//document.body.insertBefore(_e, iO);
    1310 					iO.appendChild(_e);
    1311 	}
    1312
    1313
    1314 	//	設定 childNodes
    1315 	if (tag)
    1316 		_.add_node(_e, innerObj);
    1317 	/*
    1318 	 if (tag && innerObj)
    1319 		(_i = function(_o) {
    1320 			if (typeof _o == 'object') {
    1321 				if (_o)
    1322 					if (_o instanceof Array)// &&_o.length
    1323 						for ( var _j = 0; _j < _o.length; _j++)
    1324 							_i(_o[_j]);
    1325 					else
    1326 						_e.appendChild(_o);
    1327 				return;
    1328 			}
    1329 			if (typeof _o == 'number' && !isNaN(_o))
    1330 				// _o+='';
    1331 				_o = _o.toString();
    1332 			if (typeof _o == 'string')
    1333 				if (_o.indexOf('<') != -1)
    1334 					_e.innerHTML += _o;
    1335 				else
    1336 					_e.appendChild(document.createTextNode(_o));
    1337 			//else library_namespace.warn('XML_node: Error insert contents:\n[' + _o + ']');
    1338 		})(innerObj);
    1339 	*/
    1340
    1341 	//	this helps to fix the memory leak issue
    1342 	//	http://www.hedgerwow.com/360/dhtml/ie6_memory_leak_fix/
    1343 	//	http://jacky.seezone.net/2008/09/05/2114/
    1344 	try {
    1345 		return _e;
    1346 	} finally {
    1347 		_e = null;
    1348 	}
    1349 };
    1350
    1351
    1352
    1353
    1354
    1355 CeL.interact.DOM
    1356 .
    1357 /**
    1358  * 設定 HTML element 的 text。
    1359  * 對付IE與Moz不同的text取得方法。現階段不應用innerText，應該用此函數來取得或設定內部text。
    1360  * TODO: DOM: 用.nodeValue
    1361  * @param element	HTML element
    1362  * @param {String} text	the text to be set
    1363  * @return
    1364  * @see
    1365  * http://www.klstudio.com/post/94.html
    1366  * @memberOf	CeL.interact.DOM
    1367  */
    1368 set_text=function (element, text) {
    1369 	if (!element || typeof window !== 'object' || typeof window.document !== 'object'
    1370 			|| typeof o === 'string' && !(element = _.get_element(element)))
    1371 		return;
    1372
    1373 	var text_p=_.set_text.p;
    1374 	if (typeof text_p !== 'string' || !text_p)
    1375 		_.set_text.p = text_p =
    1376 				typeof document.body.textContent === 'string' ? 'textContent'
    1377 				: typeof document.body.innerText === 'string' ? 'innerText'
    1378 				: 'innerHTML';
    1379
    1380 	var p = typeof element.value === 'string' ? 'value' : text_p;
    1381 	if (typeof text !== 'undefined')
    1382 		element[p] = text;
    1383
    1384 	//	http://www-128.ibm.com/developerworks/tw/library/x-matters41.html
    1385 	if (element.nodeType === 3 || element.nodeType === 4)
    1386 		return element.data;
    1387
    1388 	/*
    1389 	var i = 0, t = [];
    1390 	for (; i < element.childNodes.length; i++)
    1391 		t.push(set_text(element.childNodes[i]));
    1392 	return t.join('');
    1393 	*/
    1394
    1395 	return element[p];
    1396 };
    1397
    1398
    1399 /*	用在top的index.htm中，當setTopP()後指定特殊頁面	2005/1/26 21:46
    1400 set:	window.onload=setFrame;
    1401 	var setFrameTarget='MAIN',setFrameTargetSet={'menu.htm':'MENU','all.htm':'MENU','midi.htm':'MIDI'};
    1402
    1403 ** xhtml1-frameset.dtd中<script>只能放在<head>
    1404 */
    1405 var setFrameTarget,setFrameTargetSet;	//	預設target, 轉頁的target lists
    1406 //setFrame[generateCode.dLK]='setFrameTarget,setFrameTargetSet';
    1407 function setFrame(){
    1408  //alert(window.name);
    1409  //for(var i=0;i<window.frames.length;i++)alert(window.frames[i].name);
    1410  //alert(top.location.href+'\n'+location.href+'\n'+(top.location.href!=location.href)+'\n'+(window.top!=window.window));
    1411  if(window.top!=window.window){//top.location.href!=location.href
    1412   window.top.location.replace(location.href);
    1413   return;
    1414  }
    1415  var l,f;
    1416  try{l=location.hash.slice(1);}catch(e){return;}	//	IE在about:blank的情況下呼叫網頁，網頁完全載入前location無法呼叫。例如從FireFox拉進IE時使用location.*有可能'沒有使用權限'，reload即可。
    1417  if(typeof setFrameTargetSet!='object')setFrameTargetSet={};
    1418  if(l)try{l=decodeURIComponent(l);}catch(e){l=unescape(l);}
    1419  //location.hash='';	//	這一項會reload
    1420  if( l && (f=(f=l.match(/([^\/]+)$/)?RegExp.$1:l)&&(f=f.match(/^([^?#]+)/)?RegExp.$1:f)&&(l in setFrameTargetSet)?setFrameTargetSet[f]:setFrameTarget) && f!=window.name && window.frames[f] && window.frames[f].location.href!=l )
    1421   //alert(l+'\n==>\n'+f),
    1422   window.open(l,f);//if((l=window.open(l,f).top).focus(),alert(l!=self.top),l!=self.top)self.top.close();//alert(l+'\n'+f),	//	moz需要等到frame load之後才能得到window.frames[f].location.href==l的結果，所以可以考慮作setTimeout的延遲。但是假如真的不是預設的page，這樣會造成多load一遍。
    1423  //setTimeout('alert(window.frames["'+f+'"].location.href);',900);
    1424 }
    1425 /*
    1426 	set window.top page to certain location
    1427 	setTopP(location,search)
    1428 	search===setTopP_doTest: do a test, return window.top不為指定頁?1:0
    1429 */
    1430 var setTopPDTopP,setTopP_doTest=.234372464;	//	default top page(file) path
    1431 //setTopP[generateCode.dLK]='dBasePath,getFN,setTopPDTopP,setTopP_doTest';
    1432 function setTopP(l, s) {
    1433 	if (!setTopPDTopP)
    1434 		return 2;
    1435 	if (!l)
    1436 		l = dBasePath(setTopPDTopP) + getFN(setTopPDTopP);
    1437 	// alert(l);
    1438 	if (typeof s == 'undefined')
    1439 		try {
    1440 			//	IE在about:blank的情況下呼叫網頁，網頁完全載入前location無法呼叫。
    1441 			//	例如從FireFox拉進IE時使用location.*有可能'沒有使用權限'，reload即可。
    1442 			s = window/* self */.location.search;
    1443 		} catch (e) {
    1444 			return;
    1445 		}
    1446 	var t, r = /[\/\\]$/i, ri = /[\/\\](index.s?html?)?$/i;
    1447 	try {
    1448 		//	top.location.pathname在遇到local file時可能出問題。
    1449 		//	若不同domain時top.location也不能取用，應改成window.top!=window.window
    1450 		t = window.top.location.href.replace(/[?#](.*)$/, '');
    1451 	} catch (e) {
    1452 		t = '';
    1453 	}
    1454 	// alert(t+'\n'+l+'\n'+(t!=l));
    1455 	if (t != l && !(r.test(l) && ri.test(t)) && !(ri.test(l) && r.test(t)))
    1456 		if (s === setTopP_doTest)
    1457 			return 1;
    1458 		// replace() 方法可以開啟檔案，但是卻不會更動瀏覽器的瀏覽歷程（history）內容.
    1459 		// IE6若location.href長度超過2KB，光是'location.search'這項敘述就會導致異常.
    1460 		else
    1461 			// 預設page：xx/和xx/index.htm相同
    1462 			window.top.location.replace(l + s + '#'
    1463 					+ encodeURIComponent(location.href));
    1464 };
    1465
    1466
    1467 //	設在body.onload，改變IE中所有<a>在滑鼠移入移出時的 window.status
    1468 var setAstatusOS;	//	old status,也可設定event.srcElement.ostatus等等，但考慮到將造成記憶體浪費…
    1469 //setAstatus[generateCode.dLK]='setAstatusOver,setAstatusOut';
    1470 function setAstatus() {
    1471 	if (typeof window !== 'object' || typeof window.event === 'undefined' || typeof window.status === 'undefined'
    1472 			//||typeof event.srcElement=='undefined'
    1473 		)
    1474 		// 預防版本過低(4以下)的瀏覽器出現錯誤：event至IE4才出現
    1475 		return;
    1476 	var i, o, l;
    1477 	if (o = document.getElementsByTagName('a'))
    1478 		for (i = 0, l = o.length; i < l; i++)
    1479 			if (o[i].title && !o[i].onmouseover && !o[i].onmouseout)
    1480 				o[i].onmouseover = setAstatusOver,
    1481 				o[i].onmouseout = setAstatusOut;
    1482 };
    1483 //setAstatusOver[generateCode.dLK]=setAstatusOut[generateCode.dLK]='setAstatusOS';
    1484 function setAstatusOver() {
    1485 	var o = window.event.srcElement;
    1486 	if (o.title) {
    1487 		setAstatusOS = window.status, window.status = o.title;
    1488 		return true;
    1489 	}
    1490 };
    1491 function setAstatusOut() {
    1492 	//var o=event.srcElement;if(typeof o.ostatus!='undefined'){window.status=o.ostatus;return true;}
    1493 	window.status = setAstatusOS;
    1494 	return true;
    1495 };
    1496
    1497
    1498
    1499
    1500
    1501 CeL.interact.DOM
    1502 .
    1503 /**
    1504  * fill data to table.
    1505  * 增加 table 的列(row)
    1506  * @param {Array|Object} data	data list
    1507  * @param table	table element
    1508  * @param {Array} header	header list
    1509  * @return
    1510  * @example
    1511  * table_list([list1],[list2],..)
    1512  * e.g.,	table_list([1,2,3,4],[4,5,3,4]);
    1513  * table_list([[list1],[list2],..])
    1514  * e.g.,	table_list( [ [1,2,3,4],[4,5,3,4] ] );
    1515  * @since	2010/05/03 14:13:18
    1516  * @memberOf	CeL.interact.DOM
    1517  * @see
    1518  * http://www.datatables.net/
    1519  */
    1520 table_list = function(data, table, header, do_clean) {
    1521 	var i = 0, l, add_list = function(array, d) {
    1522 		if (!library_namespace.is_Array(array))
    1523 			return;
    1524
    1525 		var j = 0, tr = document.createElement('tr'), td, array, L = array.length;
    1526 		for (; j < L; j++) {
    1527 			td = document.createElement(d || 'td');
    1528 			td.appendChild(document.createTextNode(array[j]));
    1529 			tr.appendChild(td);
    1530 		}
    1531 		table.appendChild(tr);
    1532 	};
    1533
    1534 	if (typeof table === 'string')
    1535 		table = document.getElementById(table);
    1536
    1537 	/*
    1538 	//	in  Chrome/5.0.342.9 @ Ubuntu, 加了會出問題。
    1539 	try{
    1540 		if(l=table.getElementsByTagName('tbody'))
    1541 			table=l[0];
    1542 	}catch(e){}
    1543 	*/
    1544
    1545 	if (do_clean)
    1546 		table.innerHTML = '';
    1547 		/*
    1548 		try {
    1549 			// moz
    1550 			table.innerHTML = '';
    1551 		} catch (e) {
    1552 			try {
    1553 				// alert(table.rows.length);
    1554 				// IE
    1555 				for ( var i = table.rows.length; i > 0;)
    1556 					table.deleteRow(--i);
    1557 			} catch (e) {
    1558 			}
    1559 		}
    1560 		*/
    1561
    1562 	if (header)
    1563 		add_list(header, 'th');
    1564
    1565 	if (data.length === 1 && typeof (l=data[0]) === 'object'
    1566 			&& library_namespace.is_Array(l[0]))
    1567 		data = l;
    1568
    1569 	if (library_namespace.is_Array(data))
    1570 		for (l = data.length; i < l; i++) {
    1571 			add_list(data[i]);
    1572 		}
    1573 	else if (library_namespace.is_Object(data)) {
    1574 		for (i in data) {
    1575 			add_list( [ i, data[i] ]);
    1576 		}
    1577 	} else
    1578 		library_namespace.debug('Error input: not legal data!');
    1579 };
    1580
    1581
    1582
    1583 /*
    1584
    1585 test:
    1586 /fsghj.sdf
    1587 a.htm
    1588 http://www.whatwg.org/specs/web-apps/current-work/#attr-input-pattern
    1589 file:///D:/USB/cgi-bin/lib/JS/_test_suit/test.htm
    1590 //www.whatwg.org/specs/web-apps/current-work/#attr-input-pattern
    1591
    1592 TODO:
    1593 .fileName:
    1594 file:///D:/USB/cgi-bin/lib/JS/_test_suit/test.htm
    1595 ->
    1596 D:\USB\cgi-bin\lib\JS\_test_suit\test.htm
    1597
    1598 eURI : /^((file|telnet|ftp|https?)\:\/\/|~?\/)?(\w+(:\w+)?@)?(([-\w]+\.)+([a-z]{2}|com|org|net))?(:\d{1,5})?(\/([-\w~!$+|.,=]|%[a-f\d]{2})*)?(\?(([-\w~!$+|.,*:]|%[a-f\d{2}])+(=([-\w~!$+|.,*:=]|%[a-f\d]{2})*)?&?)*)?(#([-\w~!$+|.,*:=]|%[a-f\d]{2})*)?$/i,
    1599
    1600 */
    1601 CeL.interact.DOM
    1602 .
    1603 /**
    1604  * Parses URI
    1605  * @param {String} URI	URI to parse
    1606  * @return	parsed object
    1607  * @example
    1608  * alert(parse_URI('ftp://user:cgh@dr.fxgv.sfdg:4231/3452/dgh.rar?fg=23#hhh').hostname);
    1609  * @since	2010/4/13 23:53:14 from parseURI+parseURL
    1610  * @memberOf	CeL.interact.DOM
    1611  * @see
    1612  * RFC 1738, RFC 2396, RFC 3986,
    1613  * Uniform Resource Identifier (URI): Generic Syntax,
    1614  * http://tools.ietf.org/html/rfc3987,
    1615  * http://flanders.co.nz/2009/11/08/a-good-url-regular-expression-repost/,
    1616  * http://www.mattfarina.com/2009/01/08/rfc-3986-url-validation,
    1617  * also see batURL.htm
    1618  */
    1619 parse_URI = function(URI) {
    1620 	var m, n, h = URI, p;
    1621 	if (!h
    1622 			||
    1623 			// 不能用 instanceof String!
    1624 			typeof h !== 'string'
    1625 				|| !(m = h.match(/^([\w\d\-]{2,}:)?(\/\/)?(\/[A-Za-z]:|[^\/#?&\s:]+)([^\s:]*)$/)))
    1626 		return;
    1627 	//library_namespace.debug('parse [' + URI + ']: '+m);
    1628
    1629 	URI = is_DOM('location') ? {
    1630 		// protocol包含最後的':',search包含'?',hash包含'#'
    1631 		// file|telnet|ftp|https
    1632 		protocol : location.protocol,
    1633 		hostname : location.hostname,
    1634 		port : location.port,
    1635 		host : location.host,
    1636 		//	local file @ IE: C:\xx\xx\ff, others: /C:/xx/xx/ff
    1637 		pathname : location.pathname
    1638 	} : {};
    1639 	URI.URI = h;
    1640
    1641 	if (n = m[1])
    1642 		URI.protocol = n;
    1643 	URI._protocol = URI.protocol.slice(0,-1);
    1644 	//library_namespace.debug('protocol [' + URI._protocol + ']');
    1645
    1646 	/*	** filename 可能歸至m[4]!
    1647 	 * 判斷準則:
    1648 	 * gsh.sdf.df#dhfjk		filename|hostname
    1649 	 * gsh.sdf.df/dhfjk		hostname
    1650 	 * gsh.sdf.df?dhfjk		filename
    1651 	 * gsh.sdf.df			filename
    1652 	 */
    1653 	h = m[3], p = m[4];
    1654 	if (h && !/^\/[A-Za-z]:$/.test(h) && (p.charAt(0) === '/' || /[@:]/.test(h))) {
    1655 		// 處理 username:password
    1656 		if (m = h.match(/^([^@]*)@(.+)$/)) {
    1657 			n = m[1].match(/^([^:]+)(:(.*))?$/);
    1658 			if (!n)
    1659 				return;
    1660 			URI.username = n[1];
    1661 			if (n[3])
    1662 				URI.password = n[3];
    1663 			h = m[2];
    1664 		}
    1665
    1666 		// 處理 host
    1667 		if (m = h.match(/^([^\/#?&\s:]+)(:(\d{1,5}))?$/)) {
    1668 			// host=hostname:port
    1669 			URI.host = URI.hostname = m[1];
    1670 			if (m[3])
    1671 				URI.port = parseInt(m[3], 10);
    1672 			else if (n = {
    1673 						http : 80,
    1674 						ftp : 21
    1675 					}[URI._protocol])
    1676 				URI.host += ':' + (URI.port = n);
    1677 		} else
    1678 			return;
    1679
    1680 	} else//	test URI.protocol === 'file:'
    1681 		p = h + p, h = '';
    1682 	//if (!h) library_namespace.warn('將[' + p + ']當作 pathname!');
    1683 	//library_namespace.debug('local file: [' + location.pathname + ']'),
    1684
    1685 	if(!/^([^%]+|%[a-f\d]{2})+$/.test(p))
    1686 		library_namespace.warn('encoding error: [' + p + ']');
    1687
    1688 	if (p && (m = p.match(/^(((\/.*)\/)?([^\/#?]*))?(\?([^#]*))?(#(.*))?$/)))
    1689 		// pathname={path}filename
    1690 		//library_namespace.warn('pathname: [' + m + ']'),
    1691 		//	.path 會隨不同 OS 之 local file 表示法作變動!
    1692 		URI.path = /^\/[A-Za-z]:/.test(URI.pathname = m[1]) ? m[2].slice(1).replace(/\//g,'\\') : m[2],
    1693 		URI.filename = m[4],
    1694 		URI.search = m[5], URI._search = m[6],
    1695 		URI.hash = m[7], URI._hash = m[8];
    1696 	else {
    1697 		if (!h)
    1698 			return;
    1699 		URI.path = URI.pathname.replace(/[^\/]+$/, '');
    1700 	}
    1701 	//library_namespace.debug('path: [' + URI.path + ']'),
    1702
    1703
    1704 	// href=protocol:(//)?username:password@hostname:port/path/filename?search#hash
    1705 	URI.href = (URI.protocol ? URI.protocol + '//' : '')
    1706 	+ (URI.username ? URI.username
    1707 			+ (URI.password ? ':' + URI.password : '') + '@' : '')
    1708 			+ URI.host + URI.pathname + (URI.search || '') + (URI.hash || '');
    1709
    1710 	//library_namespace.debug('href: [' + URI.href + ']');
    1711 	return URI;
    1712 };
    1713
    1714
    1715
    1716
    1717
    1718
    1719 /*	Copy id(or object) to user's clipboard or Paste clipboard to id(or object).
    1720
    1721 	return the value set to clipboard
    1722 	http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_textrange.asp
    1723 	http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/textrange.asp
    1724 	http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/execcommand.asp
    1725 	way 2:use window.clipboardData	http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/clipboarddata.asp
    1726
    1727 	clipboardFunction()	paste/get clipboard
    1728 	clipboardFunction(0,divObj)	paste/get clipboard to divObj
    1729 	clipboardFunction(1,'divObj name')	Copy divObj to clipboard/set clipboard
    1730 	clipboardFunction(2,'dcfvdf')	set clipboard by string
    1731 	clipboardFunction(3,divObj)	Copies divObj to the clipboard/set clipboard and then deletes it. *return the value set to clipboard
    1732 */
    1733 var clipboardFunctionObj = 'clipboardFunctionDiv';
    1734 //clipboardFunction[generateCode.dLK]='clipboardFunctionObj';
    1735 function clipboardFunction(m,o){	//	method,object/(string)set value
    1736 if(window.navigator.appName=="Microsoft Internet Explorer"){
    1737  var t,O,tN;
    1738  if(m==2)t=o,o='';else if(typeof o=='string')o=document.getElementById(o);
    1739  //	try .nodeName instead of .tagName	http://twpug.net/modules/smartsection/item.php?itemid=35
    1740  if((typeof o!='object'||!o||(tN=(o.tagName||'').toLowerCase())!='textarea'&&tN!='select'&&tN!='option'&&(tN!='input'||o.type!='text')&&(O=o))&&!(o=document.getElementById(clipboardFunctionObj)))	//	textarea,select,option,input需使用.value!	o.type!='INPUT'||o.type!='text'：這樣大概也沒copy的價值了吧，應該會出現錯誤。
    1741   try{document.body.appendChild(o=document.createElement('textarea')),o.id=clipboardFunctionObj;}catch(e){return;}	//	只對IE5.5之後有用
    1742  //var t=document.body.createTextRange();t.moveToElementText(o);
    1743  if(m==2)o.value=t;else{if(O)o.value=O.innerText;if(m==3)t=o.value;}
    1744  if(o.id==clipboardFunctionObj)o.style.display='block';	//	得出現才能execCommand()
    1745  o.createTextRange()//TextRange Object
    1746 	.execCommand(m?m==3?"Cut":"Copy":"Paste");
    1747  if(o.id==clipboardFunctionObj)o.style.display='none';
    1748  //t.execCommand("ForeColor","false","plum"),t.execCommand("BackColor","false","glay");
    1749  //alert(o.tagName+'\n'+o.id+'\n['+o.innerText+']\n'+(m?m==3?"Cut":"Copy":"Paste"));
    1750  if(m!=3)t=o.value;
    1751  if(O)O.innerText=o.value;
    1752  return t;
    1753 }
    1754
    1755 //	http://www.mozilla.org/xpfe/xptoolkit/clipboard.html
    1756 //	http://mozilla.org/editor/midasdemo/securityprefs.html
    1757 //	http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/06/21/4850.aspx
    1758 //	http://www.webdeveloper.com/forum/archive/index.php/t-170520.html
    1759 //	http://forum.moztw.org/viewtopic.php?p=131407
    1760 /*
    1761 if(window.navigator.appName=="Netscape"){	//	…不能用！
    1762  if(typeof o=='string')o=document.getElementById(o);
    1763  if(m==2||!o||o.tagName!='TEXTAREA'&&o.tagName!='SELECT'&&o.tagName!='OPTION'&&(o.tagName!='INPUT'||o.type!='text'))return;	//	無法設定
    1764
    1765  if(!Zwischenablage){	//	初始設定
    1766   netscape.security.PrivilegeManager.enablePrivilege("UniversalSystemClipboardAccess");
    1767   //var fr=new java.awt.Frame();
    1768   Zwischenablage=new java.awt.Frame().getToolkit().getSystemClipboard();
    1769  }
    1770
    1771  if(m==0){
    1772   var Inhalt=Zwischenablage.getContents(null);
    1773   if(Inhalt!=null)o.value=Inhalt.getTransferData(java.awt.datatransfer.DataFlavor.stringFlavor);
    1774  }
    1775  else{	//	m=1,3
    1776   o.select();
    1777   Zwischenablage.setContents(new java.awt.datatransfer.StringSelection(o.value),null);
    1778  }
    1779
    1780  return o.value;
    1781 }
    1782 */
    1783 }	//	clipboardFunction()
    1784
    1785
    1786
    1787
    1788 Clipboard = function() {
    1789 };
    1790
    1791
    1792 CeL.interact.DOM
    1793 .
    1794 //	2010/1/15 00:17:38
    1795 //	IE, FF only
    1796 //	http://www.jeffothy.com/weblog/clipboard-copy/
    1797 //	http://bravo9.com/journal/copying-into-the-clipboard-with-javascript-in-firefox-safari-ie-opera-292559a2-cc6c-4ebf-9724-d23e8bc5ad8a/
    1798 //	http://code.google.com/p/zeroclipboard/
    1799 copy_to_clipboard = function(text) {
    1800 	var clip;
    1801 	if (clip = window.clipboardData) {
    1802 		clip.clearData();
    1803 		clip.setData('Text', text);
    1804 	} else if (is_DOM('Components')){
    1805 		library_namespace.require_netscape_privilege(
    1806 			//	在您的機器上執行或安裝軟體
    1807 			'UniversalXPConnect', function() {
    1808 			//	https://developer.mozilla.org/en/Using_the_Clipboard
    1809 			//	[xpconnect wrapped nsIClipboardHelper]
    1810 			return Components.classes["@mozilla.org/widget/clipboardhelper;1"]
    1811 					.getService(Components.interfaces.nsIClipboardHelper)
    1812 					//	跳出函數即無效，因此不能 cache。
    1813 					.copyString(text);
    1814 		});
    1815 	}
    1816 	//else if (navigator.userAgent.indexOf("Opera") != -1)
    1817 	//	window.location = text;
    1818 };
    1819
    1820
    1821
    1822 /*	2009/5/13 21:21:49
    1823 	unfinished
    1824 */
    1825 function clipB() {
    1826 }
    1827 clipB.start_op = function() {
    1828 	var o = this.temp_obj;
    1829 	if (!o) {
    1830 		document.body.appendChild(o = document.createElement('div'));
    1831 		// for modify
    1832 		o.contentEditable = true;
    1833 		// o.style.height=0;o.style.width=0;
    1834 		this.temp_obj = o;
    1835 	}
    1836
    1837 	document.selection.empty();
    1838 	// initial
    1839 	o.innerHTML = '';
    1840 	// 得出現才能 focus(), execCommand()
    1841 	o.style.display = 'block';
    1842 	o.focus();
    1843 	return o;
    1844 };
    1845 clipB.end_op = function() {
    1846 	var o = this.temp_obj;
    1847 	document.selection.empty();
    1848 	if (o)
    1849 		o.style.display = 'none';
    1850 };
    1851 //	return [text, obj]
    1852 clipB.get_obj = function(t) {
    1853 	var o;
    1854 	if (typeof t == 'object' && 'innerHTML' in t
    1855 			|| (o = document.getElementById('' + t)) && (t = o))
    1856 		return [ t.innerHTML, t ];
    1857 	return [ t ];
    1858 };
    1859 clipB.paste_to = function(o) {
    1860 	o = this.get_obj(o);
    1861 	if (o = o[1])
    1862 		o.innerHTML = this.get(1);
    1863 };
    1864 clipB.set = function(o) {
    1865 	o = this.get_obj(o);
    1866 };
    1867 //	get HTML
    1868 clipB.get = function(h) {
    1869 	var o = this.start_op(), r = document.selection.createRange(), t;
    1870 	r.select();
    1871 	r.execCommand('Paste');
    1872 	t = h ? r.htmlText : r.text;
    1873 	this.end_op();
    1874 	return h ? o.innerHTML : o.innerText;
    1875 };
    1876 clipB.cut_from = function(o) {
    1877 	o = this.get_obj(o);
    1878 };
    1879
    1880
    1881 //從後面調過來的
    1882 var disabledKM=0,scrollToXY,scrollToInterval,scrollToOK,doAlertDivName,doAlertOldScrollLocation;
    1883
    1884
    1885 CeL.interact.DOM
    1886 .
    1887 /**
    1888  * 設定document.cookie.
    1889  * You can store up to 20 name=value pairs in a cookie, and the cookie is always returned as a string of all the cookies that apply to the page.
    1890  * TODO:
    1891  * HTML5 localStorage (name/value item pairs).
    1892  * test various values.
    1893  * document.cookie.setPath("/");
    1894
    1895  * @example
    1896 	範例：
    1897 //	delete domain
    1898 set_cookie('domain',0);
    1899 //	一個月(30 days)
    1900 set_cookie('expires',30);
    1901 //	設定name之值為jj
    1902 set_cookie(name,'jj');
    1903 //	設定name之值為56
    1904 set_cookie(name,56);
    1905 //	除去name
    1906 set_cookie(name);
    1907 //	設給本host全部使用
    1908 set_cookie(_.set_cookie.f.set_root);
    1909 //	設給本domain使用
    1910 set_cookie(_.set_cookie.f.set_domain);
    1911 //	依現有設定除去所有值
    1912 set_cookie(_.set_cookie.f.delete_all);
    1913 //	除去所有值
    1914 set_cookie(_.set_cookie.f.delete_all_root);
    1915 //	永久儲存（千年）
    1916 set_cookie(_.set_cookie.f.forever);
    1917 //	準確設定這之後只在這次瀏覽使用這些cookie，也可用set_cookie('expires',-1);
    1918 set_cookie(_.set_cookie.f.moment);
    1919 //	將expires設定成forever或moment後再改回來（不加expires設定）
    1920 set_cookie('expires',0);
    1921
    1922  * @param {String|Object|_module_.set_cookie.f} name	set_cookie.f flag | varoius name
    1923  * @param value	varoius value
    1924  * @param {Boolean|Object} config	若對於特殊設定僅暫時設定時，設定此項。
    1925  * @returns
    1926  * @see
    1927  * Chrome doesn't support cookies for local files unless you start it with the --enable-file-cookies flag.
    1928  * chrome.exe --allow-file-access-from-files --enable-extension-timeline-api --enable-file-cookies
    1929  * http://stackoverflow.com/questions/335244/why-does-chrome-ignore-local-jquery-cookies
    1930  * http://code.google.com/p/chromium/issues/detail?id=535
    1931  * @memberOf	CeL.interact.DOM
    1932  */
    1933 set_cookie = function (name, value, config) {
    1934 	if (!is_DOM('document') || typeof document.cookie !== 'string'
    1935 				|| typeof name === 'undefined')
    1936 		return;
    1937
    1938 	var _s = _.set_cookie, flag = _s.f, m;
    1939 	if (!config)
    1940 		//	預設傳到 default
    1941 		config = _s.c;
    1942 	else if (!library_namespace.is_Object(config))
    1943 		//	document.cookie 不須每次詳細設定，但這樣可以選擇 {} / {..} / true
    1944 		config = library_namespace.extend(_s.c, {});
    1945
    1946 	if (library_namespace.is_Object(name)) {
    1947 		for ( var i in name)
    1948 			_s(i, name[i], config);
    1949 		return config;
    1950 	}
    1951
    1952 	try {
    1953 		//	This will cause error in Phoenix 0.1:
    1954 		// Error: uncaught exception: [Exception... "Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIDOMNavigator.cookieEnabled]"  nsresult: "0x8000ffff (NS_ERROR_UNEXPECTED)"  location: "JS frame :: http://lyrics.meicho.com.tw/game/game.js :: set_cookie :: line 737"  data: no]
    1955 		if (window.navigator && !window.navigator.cookieEnabled)
    1956 			throw 1;
    1957 	} catch (e) {
    1958 		CeL.warn('set_cookie: We cannot use cookie!');
    1959 		return;
    1960 	}
    1961
    1962 	//library_namespace.debug('set_cookie: ' + name + ' = [' + value + ']', 1);
    1963 	if (name === flag.set_root)
    1964 		// 設給本 host 全部使用
    1965 		name = 'path', value = '/';
    1966 	else if (name === flag.set_domain)
    1967 		// 設給本 domain 使用，尚不是很好的判別法。
    1968 		name = 'domain', value = location.hostname.replace(/^[^.]+\./, '.');
    1969 	else if (name === flag.forever)
    1970 		// 永久儲存，date之time值不能>1e16
    1971 		name = 'expires', value = 1e14;
    1972 	else if (name === flag.moment)
    1973 		// 準確設定這之後只在這次瀏覽使用這些cookie
    1974 		name = 'expires', value = -1;
    1975
    1976 	// detect special config / 特殊設定
    1977 	if (typeof name === 'string'
    1978 			&& (m = name.match(/^(expires|path|domain|secure)$/i))) {
    1979 		name = m[1];
    1980 		if (name === 'expires' && typeof value === 'number' && value) {
    1981 			//if(value<8000)value*=86400000;//幾日，86400000=1000*60*60*24
    1982 			//value=(new Date(value<3e13?(new Date).getTime()+value:1e14)).toUTCString();	//	3e13~千年
    1983 			value = (new Date(value < 1e14 ? value < 0 ? 0 : (new Date).getTime()
    1984 					+ (value < 8e3 ? value * 86400000 : value) : 1e14)).toUTCString();
    1985 		}
    1986 		config[name] = value;
    1987 		//library_namespace.debug('set_cookie: ' + name + ' = [' + value + ']', 1);
    1988 		return name + '=' + value + ';';
    1989
    1990 	} else {
    1991 		var set = name === flag.delete_all_root ? 'expires=' + (new Date(0)).toUTCString() + ';path=/;'
    1992 			: (typeof value === 'undefined' ? 'expires=' + (new Date(0)).toUTCString() + ';'
    1993 			: config.expires ? 'expires=' + config.expires + ';' : '')
    1994 				+ (config.path ? 'path=' + config.path + ';' : '')
    1995 				+ (config.domain ? 'domain=' + config.domain + ';' : '')
    1996 				+ (config.secure ? 'secure;' : '');
    1997
    1998 		if (name === flag.delete_all || name === flag.delete_all_root) {
    1999 			/*
    2000 			   var c=document.cookie;
    2001 			   while(c.match(/([^=;]+)(=[^;]{0,})?/)){
    2002 			    c=c.substr(RegExp.lastIndex);
    2003 			    if(!/expires/i.test(RegExp.$1))document.cookie=RegExp.$1+'=;'+set;
    2004 			   }
    2005 			*/
    2006 			for ( var p = document.cookie.split(';'), n, l = p.length, i = 0; i < l; i++)
    2007 				if (!/^\s*expires\s*$/i.test(n = c[i].split('=')[0]))
    2008 					document.cookie = n + '=;' + set;
    2009 			return document.cookie;
    2010
    2011 		} else {
    2012 			//	可用escape(value)/unescape()來設定，速度會比較快，但佔空間。
    2013 			//value=name+'='+(typeof value=='undefined'?'':dQuote(''+value).replace(/([\01-\11\13-\14\16-\40=;])/g,function($0,$1){var c=$1.charCodeAt(0),d=c.toString(16);return'\\x'+(c<16?'0':'')+d;}))+';'+set;
    2014 			//	2004/11/23 21:11	因為cookie儲存成中文時會fault,所以只好還是使用escape()
    2015 			value = escape(name) + '='
    2016 					+ (typeof value == 'undefined' ? '' : escape(value)) + ';'
    2017 					+ set;
    2018 			//library_namespace.debug('set_cookie: [' + value + ']', 1);
    2019 			//library_namespace.debug('set_cookie: [' + document.cookie + ']', 1);
    2020 			// 長度過長時（約4KB）會清空，連原先的值都不復存在！
    2021 			return value.length < 4096 && (document.cookie = value) ? value
    2022 					: -1;
    2023 		}
    2024
    2025 	}
    2026 };
    2027
    2028 CeL.interact.DOM
    2029 .
    2030 set_cookie.f = {
    2031 		moment : -1,
    2032 		delete_all : 2,
    2033 		delete_all_root : 3,
    2034 		set_root : 4,
    2035 		set_domain : 5,
    2036 		forever : 6
    2037 };
    2038
    2039 CeL.interact.DOM
    2040 .
    2041 //	特殊設定
    2042 set_cookie.c = {
    2043 		expires : 0,
    2044 		path : 0,
    2045 		domain : 0,
    2046 		secure : 0
    2047 };
    2048
    2049 /*	取得document.cookie中所需之值	看起來只能取得相同domain，有設定的path之cookie
    2050
    2051 	flag=0: only get the lastest matched value;
    2052 	flag=1: only get all matched in a array;
    2053 	other flag: auto detect by name
    2054
    2055 get_cookie(name);	//	取得name之值，亦可用RegExp：if(c=get_cookie())c['name1']==value1;
    2056 get_cookie('nn[^=]*');	//	取得所有nn開頭之組合
    2057 get_cookie();	//	取得所有name=value組
    2058
    2059 因為 cookie 較容易遭到竄改或是出問題，建議設定 verify。
    2060 */
    2061 CeL.interact.DOM
    2062 .
    2063 //get_cookie[generateCode.dLK]='renew_RegExp_flag';
    2064 get_cookie=function (name,flag,verify){
    2065  if(!is_DOM('document')||!document.cookie)return;
    2066  if(!name)name='[^;=\\s]+';//\w+
    2067  var c,R=name instanceof RegExp?name:new RegExp('('+escape(name)+')\\s*=\\s*([^;=\\s]*)','g')
    2068 	,m=document.cookie.match(R);
    2069  //library_namespace.debug('get_cookie: [' + R + '] = ['+m+']', 1);
    2070  //library_namespace.debug('get_cookie: [' + document.cookie + ']', 1);
    2071  if(!m)return;
    2072  if(R.global)R=library_namespace.renew_RegExp_flag(R,'-g');
    2073  if(m.length>1)
    2074 	 //	取最後一個
    2075 	 if(flag==0 || typeof flag=='undefined'&&typeof name=='string')
    2076 		 m=m.slice(-1);
    2077  //	表示不是因name為RegExp而得出之值.
    2078  //	TODO: bug: 找 "count" 可能找到 "data_count"!!
    2079  if(m.length===1&&typeof m[0]==='string'&&(c=m[0].match(R))[1]===escape(name)){
    2080 /*
    2081   if((m=c[2])&&((c=m.charAt(0))=='"'||c=="'")&&c==m.slice(-1))	//	將值為".."或'..'轉為引號中表示之值
    2082    try{
    2083     //alert('get 1:\n'+m+'\n'+unescape(m));
    2084     window.eval('c='+m);return c;
    2085    }catch(e){}
    2086   return m;
    2087 */
    2088   return unescape(c[2]);
    2089  }
    2090
    2091  var r={},v,M,i=0;
    2092  //alert(document.cookie+'\n'+R+'\n'+m.length+'\n'+m);
    2093
    2094  for(;i<m.length;i++)
    2095   if(typeof m[i]==='string'&&(M=m[i].match(R)))
    2096    r[unescape(M[1])]=unescape(M[2]);
    2097 /*
    2098  for(;i<m.length;i++){
    2099   M=m[i].match(R),v=unescape(M[2]);
    2100   if(v&&((c=v.charAt(0))=='"'||c=="'")&&c==v.slice(-1))
    2101    try{
    2102     //alert('get 2:\n'+v+'\n'+unescape(v));
    2103     window.eval('c='+v);v=c;
    2104    }catch(e){}
    2105   r[M[1]]=v;	//	有必要可用unescape()，畢竟那是模範做法。
    2106  }
    2107 */
    2108
    2109  return r;
    2110 };
    2111
    2112
    2113 /*	取得註解部份資料：這個值會連 NewLine 都保存下來
    2114 	其實IE用document.getElementsByTagName('!')就可以了，不管幾層都能到。
    2115 	註解中[!-]需要escape！IE6之div內不能沒東西，所以得加個 （並且得在前面）之後加<!-- -->才有用。
    2116
    2117 div	從哪裡開始找
    2118 level	最多往下找幾層
    2119 retType	回傳0:node本身,1:註解值
    2120 */
    2121 function get_comments(div, level, retType) {
    2122 	if (!div) div = window.document;
    2123 	var i = 0, d, _f = get_comments;
    2124 	if (isNaN(_f.endLevel)) _f.endLevel = 2;
    2125 	if (isNaN(level) || level === -1) _f.a = [], level = _f.endLevel;
    2126 	else if (typeof _f.a != 'object') _f.a = [];
    2127 	div = div.childNodes;
    2128 	for (; i < div.length; i++) {
    2129 		d = div[i]; //if(d.nodeType==8)alert(d.tagName+'\n'+d.nodeName+'\n'+d.nodeType+(d.nodeValue?'\n'+d.nodeValue.slice(0,30):''));
    2130 		if (d.tagName && d.tagName == '!') _f.a.push(retType ? d : d.text.replace(/^<!(--)?/, '').replace(/(--)?>$/, '')); //,alert(d.tagName+'\n'+d.text.slice(0,30));
    2131 		else if (d.nodeType == 8) _f.a.push(retType ? d : d.nodeValue); //alert('*	'+_f.a.length+'\n'+d.nodeValue.slice(0,30));	//	NS	http://allabout.co.jp/career/javascript/closeup/CU20040307/index.htm?FM=cukj&GS=javascript
    2132 		//	http://www.w3.org/TR/DOM-Level-2-Core/core.html
    2133 		//	ELEMENT_NODE,ATTRIBUTE_NODE,TEXT_NODE,CDATA_SECTION_NODE,ENTITY_REFERENCE_NODE,ENTITY_NODE,PROCESSING_INSTRUCTION_NODE,COMMENT_NODE,DOCUMENT_NODE,DOCUMENT_TYPE_NODE,DOCUMENT_FRAGMENT_NODE,NOTATION_NODE
    2134 		if (level && d.childNodes) _f(d, level - 1, retType);
    2135 	}
    2136 	return _f.a;
    2137 }
    2138 //window.onload=function(){get_comments();alert(get_comments.a.length);for(var i=0;i<get_comments.a.length;i++)alert('['+get_comments.a[i]+']');};
    2139
    2140
    2141
    2142
    2143
    2144
    2145 /*	background image load
    2146 	**	本函數會倒著load！請將優先度高的排後面！
    2147
    2148 new Image看起來不是個好方法…
    2149 http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/img.asp
    2150
    2151 var img=new Image(width,heighr);img.onload=function(){docImageElement.src=this.src;}img.src=__SRC__;	//	onload應在前面，預防設定onload前就已被load?
    2152
    2153 var bgLoadImgA,bgLoadImgLA;
    2154 function bgLoadImg(){
    2155  if(location.protocol=='file:')return;
    2156  if(typeof bgLoadImgA=='string'){
    2157   var s=[1];
    2158   try{s.pop();bgLoadImgA=bgLoadImgA.split(',');setTimeout('bgLoadImg();',5000);}catch(e){}	//	測試舊版可能沒有pop()功能，會出現error
    2159   return;
    2160  }
    2161  if(bgLoadImgA.length){var i=new Image(1,1);i.function(){setTimeout('bgLoadImg();',0);},i.src=typeof getObjURL=='function'?getObjURL(bgLoadImgA.pop()):bgLoadImgA.pop();bgLoadImgLA.push(i);}
    2162 }
    2163
    2164
    2165 TODO:
    2166 Javascript uses automatic garbage collection. Set to [null] as well.	http://www.thescripts.com/forum/thread95206.html
    2167 須注意 JavaScript closure and IE 4-6 memory leak! IE 7 seems to have solved the memory leaks.	http://anotherblog.spaces.live.com/blog/cns!E9C5235EBD2C699D!458.entry?ppud=0&wa=wsignin1.0
    2168 http://laurens.vd.oever.nl/weblog/items2005/closures/	http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
    2169 IE 6對於純粹的Script Objects間的Circular References是可以正確處理的，可惜它處理不了的是JScript與Native Object(例如Dom、ActiveX Object)之間的Circular References。
    2170 P.S. 2007/11/11 似乎已修正？
    2171 */
    2172
    2173 /*	bgLoadImg() Cookie版	2006/3/3 20:08
    2174 	**	本函數正著load！請將優先度高的排前面！
    2175
    2176 	To use:
    2177 	,set_cookie,get_cookie,bgLoadImgId,bgLoadImgI,bgLoadImg
    2178 	bgLoadImgId='id_of_this_session',bgLoadImgA='img_url1,img_url2,..';	//	** MUST string!
    2179 	function getObjURL(bgLoadImgA_element){return the real URL of bgLoadImgA_element;}
    2180 	window.onload="bgLoadImg();"
    2181
    2182 var bgLoadImgId='bg',bgLoadImgI;	//	loaded index
    2183 */
    2184 //bgLoadImg[generateCode.dLK]='bgLoadImgId,bgLoadImgI';
    2185 function bgLoadImg(i) {
    2186 	var bgLoadImgM = 'bgLoadImgOK_' + bgLoadImgId;
    2187 	// alert('_'+bgLoadImgM+','+bgLoadImgI)
    2188 	if (typeof bgLoadImgA != 'object') {
    2189 		// needless
    2190 		if (!bgLoadImgA || location.protocol === 'file:')
    2191 			return;
    2192 		// http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp
    2193 		var r = document.readyState;
    2194 		if (typeof r === 'string' && r !== 'complete') {
    2195 			setTimeout(bgLoadImg, 500);
    2196 			return;
    2197 		}
    2198 		// initialization
    2199 		bgLoadImgA = bgLoadImgA.replace(/,\s*,/g, ',').split(',');
    2200 		if (typeof get_cookie != 'function'
    2201 			|| get_cookie(bgLoadImgM) != bgLoadImgA.length) { // 全部OK後就別再來了。
    2202 			if (isNaN(bgLoadImgI))
    2203 				bgLoadImgI = 0;
    2204 			if (typeof r != 'string') {
    2205 				setTimeout(bgLoadImg, 5e3);
    2206 				return;
    2207 			}
    2208 		} else
    2209 			return;
    2210 	}
    2211
    2212  //if(!isNaN(i)&&!bgLoadImgA[i].complete);	//	timeout
    2213  if(!isNaN(i)&&i<bgLoadImgI-1)return;	//	防止timeout的備援
    2214
    2215  //	標記已load counter
    2216  //	假如一個圖一個圖標記，set_cookie在超過二十個之後好像就沒效了…被限制？
    2217  _.set_cookie(bgLoadImgM,bgLoadImgI);
    2218
    2219  if(bgLoadImgI==bgLoadImgA.length)bgLoadImgI++,setTimeout('bgLoadImg();',500);	//	馬上進入判別，最後一個尚未complete
    2220  else if(bgLoadImgI<bgLoadImgA.length){
    2221   var bgLoadImgURL=typeof getObjURL=='function'?getObjURL(bgLoadImgA[bgLoadImgI]):bgLoadImgA[bgLoadImgI];
    2222   //setTimeout('bgLoadImg('+bgLoadImgI+')',5e3);	//	set timeout
    2223   with(bgLoadImgA[bgLoadImgI++]=new Image(1,1))
    2224 	//	這是個多執行緒技巧：假如使用onload=bgLoadImg，有可能在下一指令碼前就已onload，這樣會造成Stack overflow
    2225 	onload=function(){setTimeout('bgLoadImg();',0);},
    2226 	src=bgLoadImgURL;
    2227   window.status='bgLoadImg ['+bgLoadImgURL+']: '+bgLoadImgI+' / '+bgLoadImgA.length+'..';
    2228  }else{
    2229 /*
    2230   var f=[];
    2231   for(i=0;i<bgLoadImgA.length;i++)if(!bgLoadImgA[i].complete)f.push(bgLoadImgA[i].src);
    2232   if(f.length)_.set_cookie(bgLoadImgM,0);
    2233   window.status='bgLoadImg '+(f.length?'end: failed '+f.length+' / '+bgLoadImgA.length+' ('+f+')':'complete!'),bgLoadImgA=0;
    2234 */
    2235 	 var f = 0;
    2236 	 for (i = 0; i < bgLoadImgA.length; i++)
    2237 		 if (!bgLoadImgA[i].complete)
    2238 			 f++;
    2239 	 if (f)
    2240 		 _.set_cookie(bgLoadImgM, 0);
    2241 	 window.status = 'bgLoadImg '
    2242 		 + (f ? 'end: failed ' + f + ' / ' + bgLoadImgA.length
    2243 				 : 'complete!'), bgLoadImgA = 0;
    2244 	}
    2245 };
    2246
    2247
    2248
    2249 /*	儲存/回存使用者輸入之form資料用。	2004/11/23 21:38
    2250 		*已測試過text(select-one,textarea,password,hidden)/radio/checkbox/select-multiple
    2251 	formIdA:	form id or id array.不輸入或輸入'',0等表示所有的form
    2252 	expires:	不輸入或輸入''表示回存，輸入0會以預設days代替，輸入<0會刪除掉cookie中這項設定。
    2253 	targetItemA:	要處理的name。例如'name,tel,email'。假如包括unselect，會處理除了targetItemA之外所有的。
    2254
    2255 	input type="checkbox"	value不能包含';'!
    2256 	password也會被儲存，得自己排除!
    2257 e.g.,
    2258 cookieForm()	recall all items of all forms
    2259 cookieForm(0,1,'email');	save all items named 'email' of all forms
    2260 cookieForm(0,'','email');	recall all items named 'email' of all forms
    2261 cookieForm(0,-1);	消除所有*版面上現有form*之紀錄
    2262
    2263 TODO:
    2264 排除名單
    2265 對於較多的entries,也許需要使用到Object[key]來代替String.indexOf(key)
    2266 */
    2267 //cookieForm[generateCode.dLK]='get_cookie,set_cookie';
    2268 function cookieForm(formIdA,expires,targetItemA){
    2269 	if (typeof document != 'object')
    2270 		return;
    2271  if(!formIdA)formIdA=document.getElementsByTagName('FORM');else if(typeof formIdA=='string')formIdA=[formIdA];
    2272  var i,n,o,dealO=function(o){	//	メソッドをプロトタイプではなく、オブジェクト自身にセットしていることです。これでは継承できませんし、ECMAScript のプロトタイプベースのセマンティクスから外れてしまいます。
    2273   for(var j=0,c=o.childNodes,sp=';',e,cn,cv,tp;j<c.length;j++){
    2274    if((e=c[j]).hasChildNodes)dealO(e);
    2275    if(e.name&&typeof e.value!='undefined'){//cv=e.tagName=='TEXTAREA'?e.innerHTML:e.value	//	TEXTAREA,SELECT,OPTION,INPUT需使用.value!
    2276     //if(!e.value&&e.text)e.value=e.text;	//	假如沒有.value,利用.text代替
    2277     if(targetItemA)if(targetItemA.unselect&&targetItemA[e.name]||!targetItemA.unselect&&!targetItemA[e.name])continue;
    2278     //alert((isNaN(expires)?'load':'save')+'\n'+n+'::'+e.name+'['+e.type+']='+e.value);
    2279     cn='cookieForm_'+n+'_'+e.name;cv=e.value;
    2280     tp=e.type.toLowerCase();//e.tagName=='INPUT'?e.type.toLowerCase():'';
    2281     if(isNaN(expires)){if(typeof(cn=get_cookie(cn))!='undefined'){
    2282      if(tp=='radio'){
    2283       if(cv==cn)e.checked=true;
    2284      }else if(tp=='checkbox'){
    2285       if(cn.indexOf(sp+cv+sp+sp)!=-1)e.checked=true;
    2286      }else if(tp=='select-multiple')
    2287       for(var i=0;i<e.options.length;i++)
    2288        e.options[i].selected=cn.indexOf(sp+e.options[i].value+sp)!=-1;
    2289      else e.value=cn;
    2290     }}else{
    2291      if(tp=='radio'){if(!e.checked)continue;}
    2292      else if(tp=='checkbox')
    2293       if(cv.indexOf(sp)!=-1)continue;	//	value不能包含sp	checkbox之cookie形式:[;value1;;value2;value3;;value4;]:value1,3:checked
    2294       else cv=((tp=get_cookie(cn))&&tp.indexOf(sp+cv+sp)==-1?tp:sp)+cv+sp+(e.checked?sp:'');
    2295      //else if(tp=='select-one')cv=e.options[e.selectedIndex].value;	//	可省略!	用.selectedIndex會比較快，但更改原文件可能會造成index錯誤
    2296      else if(tp=='select-multiple'){
    2297       cv=sp+cv+sp;
    2298       for(var i=e.selectedIndex+1;i<e.options.length;i++)
    2299        if(e.options[i].selected)cv+=e.options[i].value+sp;
    2300      }
    2301      if(expires)_.set_cookie(cn,cv);
    2302      else _.set_cookie(cn);
    2303     }
    2304    }
    2305   }
    2306  };
    2307
    2308  if(targetItemA){
    2309   o=targetItemA;targetItemA={};if(typeof o=='string')o=o.split(',');
    2310   for(i in o)targetItemA[o[i]]=1;
    2311  }
    2312  if(expires==='')expires=NaN;
    2313  if(!isNaN(expires)){
    2314   if(expires)expires=7;	//	預設days
    2315   _.set_cookie(_.set_cookie.f.set_root);	//	Gecko need this
    2316   _.set_cookie('expires',expires);
    2317  }
    2318  for(i=0;i<formIdA.length;i++)if(o=formIdA[i]){
    2319   if(typeof o=='string')o=document.getElementById(n=o);else if(!(n=o.id))n=o.name;
    2320   if(o&&(o.tagName||'').toLowerCase()=='form'&&n&&typeof n=='string')dealO(o);
    2321  }
    2322  if(!isNaN(expires))_.set_cookie('expires',0);
    2323
    2324 }
    2325
    2326
    2327 //	登入FTP	IE使用者若要上傳，請開啟FTP 站台的資料夾檢視功能。
    2328 //	<input type="text" autocomplete="off"/>
    2329 function loginFTP(n,p,path,hostname){	//	name,password
    2330  if(!hostname&&!(hostname=location.hostname))return;
    2331  if(n=='ftp'||n=='anonymous')n='';
    2332  if(!p&&n)p=window.prompt('請輸入['+n+']之密碼：');
    2333  if(p==null)return;	//	取消輸入
    2334  p='ftp://'+(n?n+(p?':'+p:'')+'@':'')+(hostname+'/'+(path||'')).replace(/\/{2,}/g,'/');
    2335  window.open(p,'ftpW');//location.href=p;	//	用location.href不能進入資料夾檢視功能
    2336 }
    2337
    2338
    2339 //	reference page set	==================
    2340
    2341 CeL.interact.DOM
    2342 .
    2343 /**
    2344  * 簡化 document.getElementById 並配合 loadReference()
    2345  * @since 2004/6/25 19:33
    2346  * @param id	所欲找尋之 element id
    2347  * @param flag
    2348  *            {HTML Object} object: 參考此 document object
    2349  *            {Number} flag: 參見 code
    2350  * @return	{HTML Object} Object
    2351  * @requires	referenceDoc,loadReferenceDone,`get_element();`
    2352  * @memberOf	CeL.interact.DOM
    2353  */
    2354 get_element = function get_element(id, flag) {
    2355 	var _s = get_element, _f = _s.f;
    2356 	if (!_f)
    2357 		// 在 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 中會出問題，所以改到函數中執行。但得先執行過一次。
    2358 		//alert('get_element: set flags get_element.f'),
    2359 		_s.f = _f = {
    2360 			//	僅參考自身頁面，default
    2361 			'self' : 0,
    2362 			//	可參考 reference page
    2363 			'ref' : 1,
    2364 			//	僅參考 reference page
    2365 			'refOnly' : 2
    2366 		};
    2367
    2368 	if (!id || typeof window !== 'object' || typeof document !== 'object'
    2369 			|| document !== window.document)
    2370 		return null;
    2371 	// if(flag)alert('get_element: '+id+','+flag);
    2372
    2373 	// 後面暫時沒用到
    2374 	// if(!flag)flag=_f.self;
    2375
    2376 	if (
    2377 			//typeof document !== 'object' ||
    2378 			!document.body)
    2379 		// document 尚未 load
    2380 		return;
    2381
    2382 	if(_.is_HTML_element(id))
    2383 		return id;
    2384
    2385 	var o;
    2386 	if (flag !== _f.refOnly)
    2387 		// 僅參考 reference page 時不設定
    2388 		o = document.getElementById ? document.getElementById(id)
    2389 			: document.all ? document.all[id]
    2390 			: document.layers ? document.layers[id]
    2391 			: window[id];
    2392 	//if(flag)alert('get_element: '+id+','+flag+'\nloadReferenceDone='+loadReferenceDone+'\nreferenceDoc: '+referenceDoc+'\no: '+o+'\nreferenceDoc.get: '+referenceDoc.getElementById(id)+'\n'+referenceDoc.body.innerHTML.slice(0,200));
    2393 	try {
    2394 		// 偶爾還是有可能'沒有使用權限'
    2395 		typeof flag === 'object' && typeof flag.getElementById === 'function' && (o = flag.getElementById(id))
    2396 		|| o
    2397 		|| flag && loadReferenceDone === 1 && (o = referenceDoc.getElementById(id));
    2398 	} catch (e) {
    2399 	}
    2400 	return o || null;
    2401 };
    2402
    2403
    2404
    2405 /*	以外掛的reference page配置data object	2004/6/25 21:01
    2406
    2407 	toUse:
    2408 	準備好reference.htm
    2409 	在需要的文件加入	window.onload="loadReference()";
    2410 	在需要的文件body加入	<iframe id="reference"></iframe>
    2411 	function setupPageR()	initial after load of reference page
    2412
    2413 	如上，再使用 get_element() 即可得到 reference.htm 中的 obj
    2414 */
    2415 var referenceDoc,loadReferenceDone;//,loadReferenceCount;
    2416 //loadReference[generateCode.dLK]='get_element,referenceDoc,loadReferenceDone,parseFunction';
    2417 function loadReference(referenceURL,iframeId){
    2418  if(loadReferenceDone||typeof location!='object'||!location.protocol||location.protocol=='https:')return;	//	https會拒絕存取，所以直接放棄。
    2419  //if(loadReferenceDone)return;	//	https會拒絕存取，所以直接放棄。
    2420  var o=_.get_element(iframeId||'reference'),thisFuncName=parseFunction().funcName;
    2421  if(typeof referenceDoc=='object' && typeof referenceDoc.document=='object' && referenceDoc.document){	//	referenceDoc is still contentWindow here.	typeof referenceDoc.document:預防使用https時產生不能讀取的權限問題。
    2422   referenceDoc=o.contentWindow.document;//referenceDoc.document;	//	遺憾：在舊版IE不能用後者。也許是因為舊版IE連contentWindow都會重造。
    2423   o=referenceDoc.body;//alert(o.innerHTML.length+'\n'+o.innerHTML);
    2424   if(o/*&&referenceDoc.body.innerHTML=='string'*/&&o.innerHTML.length){
    2425    //alert(typeof o+','+(o?typeof o.innerHTML+'('+o.innerHTML.length+')\n'+o.innerHTML.slice(0,200):'(null)'));
    2426    //	before IE5, the first argument must be a string.
    2427    //	setTimeout(function_handle,..) 不一定代表setTimeout('function_handle();',..)，可能會傳入奇異的引數！
    2428    if(typeof setupPageR=='function')setTimeout(setupPageR,9);
    2429    loadReferenceDone=1;//window.status='reference page load OK!';alert(window.status);
    2430   }else{
    2431    //try{window.status='Wait while reference page loading..3',alert(window.status+'\nURL:'+o.contentWindow.document.src+'\ncontent('+o.contentWindow.document.body.innerHTML.length+'):\n'+o.contentWindow.document.body.innerHTML);}catch(e){}
    2432    //if(!--loadReferenceCount)history.go(0);
    2433    setTimeout(thisFuncName+'();',200);
    2434   }
    2435   return;
    2436  }
    2437  if(typeof document!='object'||!document.body){	//	document尚未load
    2438   setTimeout(thisFuncName+'();',90);
    2439   return 1;
    2440  }
    2441  //o=_.get_element(iframeId||'reference');	//	原來把設定放在這，不過反正都要在前面用到…
    2442  if(!o||(o.tagName||'').toLowerCase()!='iframe'){loadReferenceDone=2;return;}	//	iframe不存在
    2443  if(!o.src)o.style.display='none',//'block',//
    2444   o.src=referenceURL;	//	for game.js: typeof relatePath=='function'?relatePath(0,'cgi-bin/game/data/reference.htm'):'data/reference.htm'
    2445
    2446  if(typeof o.contentWindow=='object'&&typeof o.contentWindow.document=='object'){	//	typeof o.contentWindow=='object'&&: for JS5	應該不能用o.contentWindow吧？怕o.contentWindow就算沒能載入文件，也會被定義
    2447   //	Martin Honnen wrote: If you load a new document then certainly the browser has to create a new document object.
    2448   referenceDoc=o.contentWindow;//.document;	o.contentWindow.document still index to a blank window here, when new document load, this point to document won't work.
    2449
    2450   //window.status='Wait while reference page loading..2';alert(window.status+'\nURL:'+o.src);
    2451   setTimeout(thisFuncName+'();',20);//loadReferenceCount=9;
    2452  }else{
    2453   //if(location.protocol=='https:')return;	//	https會拒絕存取，所以直接放棄。最晚在這就得判別
    2454   if(!referenceDoc)referenceDoc=40;	//	尚未load完成時作倒數計時..假如加上if(o.contentWindow)，這方法正確嗎?
    2455   //else if(isNaN(referenceDoc))return 3;	//	異常(for https):不能用else if(isNaN(referenceDoc))
    2456   try{
    2457    if(referenceDoc--){
    2458     //window.status='Wait while reference page loading..';alert(window.status);
    2459     setTimeout(thisFuncName+'();',300);return 2;
    2460    }else{
    2461     //window.status='reference page load FAILED!';alert(window.status);
    2462     return 4;
    2463    }
    2464   }catch(e){
    2465    return 5;	//	Error: uncaught exception: Permission denied to get property HTMLDocument.document
    2466   }
    2467  }
    2468 }
    2469 //	translate object(innerHTML) from reference page to document
    2470 //transRefObj[generateCode.dLK]='get_element';
    2471 function transRefObj(id,id2,force){
    2472  if(typeof id2!='string'&&typeof id2!='object')force=id2,id2=typeof id=='object'?id.id:id;
    2473  var o=typeof id=='object'?id:_.get_element(id,_.get_element.f.self),p;
    2474  //alert('transRefObj: '+id2+' -> '+id+'('+(force?'':'not ')+'force)\n'+o+'\ntarget:'+(o.innerHTML?'\n'+o.innerHTML.slice(0,200):' (null)'));
    2475  if( o && (force||!o.innerHTML)
    2476 	&& (p=typeof id2=='object'?id2:_.get_element(id2,_.get_element.f.refOnly)) && (force||p.innerHTML) )
    2477   try{
    2478 	//alert('transRefObj: DO '+id2+' -> '+id+'('+(force?'':'not ')+'force)\n');
    2479 	o.appendChild(p.cloneNode(true));
    2480   }catch(e){
    2481 /*
    2482    try{
    2483 	//alert('transRefObj: try2');
    2484 	var i=0;while(i<p.childNodes.length)o.appendChild(p.childNodes[i++].cloneNode(true));
    2485    }catch(e){
    2486 */
    2487 	//alert('transRefObj: try3');
    2488 	o.innerHTML=p.innerHTML;//p.cloneNode(true);	//serialize(p)	serialize方法把一个node串行化成字符串。在ie环境的具体实现上，对于XmlDocument，使用node.xml，对于HtmlDocument，使用node.outerHTML。	http://my.opera.com/gisor/blog/index.dml/tag/SVG
    2489 /*
    2490    }
    2491 */
    2492   }
    2493  return o;
    2494 }
    2495
    2496 //	↑reference page set	==================
    2497
    2498
    2499
    2500
    2501
    2502 //	設定自動捲動
    2503 var setAutoScrollTimer,setAutoScrollInterval;
    2504 //setAutoScroll[generateCode.dLK]='setAutoScrollTimer,setAutoScrollInterval';
    2505 function setAutoScroll(interval,force){
    2506  if(!force)if(typeof document!='object'||setAutoScrollTimer||document.onmousedown||document.ondblclick)return;
    2507  if(interval)setAutoScrollInterval=interval;else if(!setAutoScrollInterval&&!(setAutoScrollInterval=get_cookie('setAutoScrollInterval')))setAutoScrollInterval=200;//5,50,100,200,500
    2508  clearInterval(setAutoScrollTimer),setAutoScrollTimer=0;	//	無論如何，先把執行中的幹掉。
    2509  if(setAutoScrollInterval<0){document.onmousedown=document.ondblclick=null;return;}
    2510  document.onmousedown=function(){if(setAutoScrollTimer)window.clearInterval(setAutoScrollTimer),setAutoScrollTimer=0;};
    2511  document.ondblclick=function(){if(setAutoScrollTimer)return;setAutoScrollTimer=window.setInterval('window.scrollBy(0,1);',setAutoScrollInterval);};//window.scrollTo(0,document.body.scrollTop+1);
    2512 }
    2513
    2514
    2515 /*	捲到設定的定點，因為某些多工慢速環境中只設定一次沒有用，所以…
    2516 	下面一行調到檔案頭
    2517 var scrollToXY,scrollToInterval,scrollToOK;
    2518 */
    2519 //scrollTo[generateCode.dLK]='scrollToXY,scrollToInterval,scrollToOK,get_window_status';
    2520 function scrollTo(y,x){
    2521  //	initial
    2522  if(typeof scrollToXY!='object')scrollToXY={};
    2523
    2524  if(typeof y=='object'&&(!isNaN(y.x)||!isNaN(y.y))){if(!isNaN(y.x))scrollToXY.x=y.x;if(!isNaN(y.y))scrollToXY.y=y.y;}
    2525  else if(y instanceof Array)scrollToXY.x=y[0],scrollToXY.y=y[1];
    2526  else{if(typeof x!='undefined')scrollToXY.x=x;if(typeof y!='undefined')scrollToXY.y=y;}
    2527  if(isNaN(scrollToXY.x))scrollToXY.x=0;if(isNaN(scrollToXY.y))scrollToXY.y=0;
    2528
    2529  setTimeout('window.scrollTo(scrollToXY.x,scrollToXY.y);',9);	//	main function
    2530  var _w=get_window_status();
    2531  //status=scrollToInterval+','+scrollToOK+';'+_w.scrollX+','+scrollToXY.x+';'+_w.scrollY+','+scrollToXY.y;
    2532  if(_w.scrollX==scrollToXY.x&&_w.scrollY==scrollToXY.y){
    2533   if(!--scrollToOK&&scrollToInterval)window.clearInterval(scrollToInterval),scrollToInterval=0;
    2534  }else if(!scrollToInterval)scrollToInterval=window.setInterval(scrollTo,90),scrollToOK=3;	//	預防萬一：總會跳回原處
    2535 }
    2536
    2537 /*	doAlert() & doAlertAccess：彈出使用注意事項視窗
    2538 	下面一行調到檔案頭
    2539 var doAlertDivName,doAlertOldScrollLocation;
    2540
    2541 TODO
    2542 設定其不可作用之 background object
    2543
    2544 	使用方法：
    2545 <head>
    2546 <script type="text/javascript" src="function.js"></script>
    2547 <script type="text/javascript">
    2548 window.onload=init;window.onscroll=window.onresize=doAlertScroll;
    2549 function init(){doAlertInit('kousi');}
    2550 </script>
    2551
    2552 <style type="text/css"><!--
    2553
    2554 /*	kousi用	加上filter:alpha(opacity=10);：因為IE5.5不吃DXImageTransform.Microsoft.Alpha，這樣用不能以.filters.alpha.opacity控制。	* /
    2555 #kousi{color:blue;background:#e2e0f8;border:double 3px red;padding:.5em;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80,Style=0);filter:Alpha(Opacity=80,Style=0);z-index:2;overflow:auto;}
    2556 #kousiBg{background:blue;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=30,Style=0);filter:Alpha(Opacity=30,Style=0);z-index:1;}
    2557 #kousiI{color:brown;background-color:#e6e6ff;cursor:pointer;border:1 solid red;white-space:nowrap;padding:2px;margin:2px;filter:Alpha(Opacity=80,Style=0);}
    2558
    2559 #kousi h2{color:brown;margin-left:2em;}
    2560 #kousi input{color:#114f12;background-color:#fddbfb;border:1 brown solid;}
    2561
    2562 --></style>
    2563 </head>
    2564
    2565 <body>
    2566 <!--div id="kousiBg"></div--><div id="kousi">
    2567 <h2>使用注意事項</h2>
    2568
    2569 注意事項
    2570
    2571 <hr style="color:#928cd9"/>
    2572 <table style="width:90%;text-align:center;"><tr><td><input type="button" onclick="top.location.href='http://www.hinet.net';" value="誰管你！"/></td>
    2573 <td><input type="button" onclick="doAlertAccess();//this.parentNode.parentNode.parentNode.parentNode.parentNode.id" value="我願意遵守上述規定"/></td>
    2574 <td><input type="button" onclick="set_cookie(set_cookie.f.forever),set_cookie('doAlert',doAlertDivName),doAlertAccess();" value="我往後皆會遵守上述規定"/></td></tr></table>
    2575 </div>
    2576
    2577 <a href="#" onclick="doAlert();">注意事項</a>
    2578
    2579 正文
    2580
    2581 </body>
    2582 */
    2583 function doAlertResize(){	//	確保置中
    2584  if(typeof doAlertDivName!='string'||!doAlertDivName||!(o=document.getElementById(doAlertDivName)))return;
    2585  with(o.style){
    2586   position='absolute',display='block',width='70%';
    2587 /*	因為'%'是以整體長寬為主，故不適用。
    2588   var t=Math.round(50*(1-o.offsetHeight/document.body.clientHeight));
    2589   if(t<0)width='99%',top='0';else top=t+'%';
    2590   t=Math.round(50*(1-o.offsetWidth/document.body.clientWidth));
    2591   left=t<0?'0':t+'%';
    2592 */
    2593   //alert(offsetHeight+','+window.offsetHeight+','+window.innerHeight+','+window.outerHeight);
    2594   if(typeof window.innerHeight=='undefined')window.innerHeight=document.body.clientHeight;
    2595   if(typeof window.innerWidth=='undefined')window.innerWidth=document.body.clientWidth;
    2596   var t=(window.innerHeight-o.offsetHeight)/2;
    2597   if(t<0)width=height='99%',top=0;else top=t+'px';
    2598   t=(window.innerWidth-o.offsetWidth)/2;
    2599   left=t<0?0:t+'px';	//	不用marginTop與marginLeft，因為這裡要放置div
    2600  }
    2601 }
    2602 //	初始化
    2603 //doAlertInit[generateCode.dLK]='set_cookie,doAlert';
    2604 function doAlertInit(n){	//	n:div name
    2605  //if(typeof doAlertDone!='undefined'&&doAlertDone)return;	//	防止重複執行
    2606  if(!n){	//	doAlertInit()重設
    2607 	 _.set_cookie(_.set_cookie.f.set_root);	//	Gecko need this
    2608 	 _.set_cookie('doAlert');
    2609   return;
    2610  }
    2611  var d=document.getElementById(n);
    2612  if(d){
    2613   if(typeof doAlertDivName=='undefined')doAlertDivName=n;
    2614   doAlert();
    2615  }
    2616 }
    2617 //	出現警告
    2618 //doAlert[generateCode.dLK]='doAlertInit,doAlertResize,doAlertAccess,doAlertScroll,doAlertDivName,doAlertOldScrollLocation,get_cookie,get_window_status';
    2619 function doAlert(n,m,iconContent){	//	n:name,m:mode=1:use alert(),icon div的文字內容
    2620  if(!n&&typeof doAlertDivName=='string'&&doAlertDivName)n=doAlertDivName;
    2621  var o=document.getElementById(n),oBg=document.getElementById(n+'Bg'),oI=document.getElementById(n+'I');
    2622  if(!document.body||!o||m&&!alert(o.innerHTML))return;	//	alert()會return undefined
    2623  if(!oI)try{
    2624   o.parentNode.insertBefore(oI=document.createElement('div'),o);//document.body.insertBefore();
    2625   oI.id=n+'I';oI.onclick=function(){doAlertInit();doAlert();};oI.title="注意事項";
    2626   oI.innerHTML=iconContent||'別忘了';oI.doAlertScrollT=oI.doAlertScrollL=0;
    2627  }catch(e){return;}	//	只對IE5.5之後有用
    2628  if(!oBg)try{o.parentNode.insertBefore(oBg=document.createElement('div'),o);oBg.id=n+'Bg';}catch(e){return;}	//	只對IE5.5之後有用
    2629  //if(!oI||!oBg)alert('No index or bg div!');
    2630  disableKM(2);doAlertResize();window.Oonresize=window.onresize,window.onresize=doAlertResize;
    2631  with(oI.style)display='none',position='absolute',right='.1em',top='.1em';
    2632  with(oBg.style)position='absolute',left=-parseInt(document.body.leftMargin),top=-parseInt(document.body.topMargin),width=height='110%',display='inline';	//	offset*:唯讀
    2633  if(o.filters)o.filters.alpha.opacity=85;//try{o.filters.alpha.opacity=85;}catch(e){}
    2634  if(oBg.filters)try{oBg.filters.alpha.opacity=30;}catch(e){}
    2635  else{	//	for Moz
    2636   o.style.position='fixed';
    2637   with(oBg.style)position='fixed',opacity=oBg.style['-moz-opacity']=.3,left=top=0,width=height='100%';
    2638  }
    2639  if(get_cookie('doAlert')==n)doAlertAccess(n);
    2640  else o=get_window_status(),doAlertOldScrollLocation=[o.scrollX,o.scrollY],setTimeout('scrollTo(0,0);',0);	//	奇怪的是，直接執行scrollTo(0,0)沒啥用。
    2641 }
    2642 //	pass
    2643 function doAlertAccess(n){
    2644  if(!n&&typeof doAlertDivName=='string'&&doAlertDivName)n=doAlertDivName;
    2645  var o=document.getElementById(n),oBg=document.getElementById(n+'Bg');
    2646  if(oBg)oBg.style.display='none';o.style.display='none';
    2647  disableKM(0);
    2648  window.onresize=window.Oonresize||null;
    2649  if(doAlertOldScrollLocation)scrollTo(doAlertOldScrollLocation,0,1);
    2650  doAlertScroll(1);
    2651 }
    2652 //	icon div的捲動：置於右上角
    2653 //doAlertScroll[generateCode.dLK]='get_window_status';
    2654 function doAlertScroll(m){var oI;
    2655  if(typeof doAlertDivName!='string'||!doAlertDivName||!(oI=document.getElementById(doAlertDivName+'I')))return;
    2656  if(typeof m!='undefined'){
    2657   oI.style.display=m?'block':'none';
    2658   oI.doAlertScrollL=oI.offsetWidth+(m||0);
    2659   if(oI.currentStyle){	//	IE
    2660    if(m=parseInt(oI.currentStyle.paddingTop))oI.doAlertScrollT=m;
    2661    m=parseInt(oI.currentStyle.paddingLeft);
    2662    if(m=parseInt(oI.currentStyle.paddingRight))oI.doAlertScrollL+=m;
    2663   }else{
    2664    oI.style.position='fixed';
    2665 /*	//	Moz..but no use
    2666    if(m=oI.offsetTop)oI.doAlertScrollT=m;
    2667    m=oI.offsetLeft;
    2668    if(m=oI.offsetRight)oI.doAlertScrollL+=m;
    2669 */
    2670   }
    2671  }
    2672  //window.status=m=window.scrollX+','+window.scrollY+','+window.innerWidth+','+window.innerHeight+';'+document.body.scrollLeft+','+document.body.scrollTop+','+document.body.offsetWidth+','+document.body.clientWidth+','+oI.offsetWidth+','+document.body.scrollWidth;alert(m);
    2673  m=get_window_status();
    2674  oI.style.left=m.scrollX+m.windowW-oI.doAlertScrollL+'px';//-document.body.leftMargin-document.body.rightMargin
    2675  oI.style.top=m.scrollY-oI.doAlertScrollT+'px';	//	只有在padding用px時有效！
    2676 }
    2677
    2678
    2679 CeL.interact.DOM
    2680 .
    2681 /**
    2682  * Sets / adds class of specified element.<br/>
    2683  * TODO:<br/>
    2684  * 1. 一次處理多個 className。<br/>
    2685  * 2. 以字串處理可能較快。<br/>
    2686  * 3. 用 +/- 設定。<br/>
    2687  * 4. https://developer.mozilla.org/en/DOM/element.classList
    2688  * @param element	HTML elements
    2689  * @param class_name	class name || {class name 1:, class name 2:, ..}
    2690  * @param flag
    2691  * default: just add the specified className
    2692  * (flag&1)==1:	reset className (else just add)
    2693  * (flag&2)==1:	return {className1:, className2:, ..}
    2694  * (flag&4)==1:	remove className
    2695  * @return
    2696  * @see
    2697  * <a href="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-95362176" accessdate="2009/12/14 22:26">className of type DOMString</a>,
    2698  * <a href="https://developer.mozilla.org/En/DOM/Element.className" accessdate="2009/12/14 22:27">element.className - MDC</a>
    2699  * @memberOf	CeL.interact.DOM
    2700  */
    2701 set_class = function(element, class_name, flag) {
    2702 	if (typeof element === 'string')
    2703 		element = document.getElementById(element);
    2704
    2705 	if (typeof element !== 'object' || !element || typeof element.className !== 'string')
    2706 		return;
    2707 	// if(!flag)flag=0;
    2708 	var c, remove = (flag & 4) == 4;
    2709
    2710 	if (class_name && !remove) {
    2711 		c = class_name instanceof Array ? class_name.join(' ') : class_name;
    2712 		if (flag & 1)
    2713 			element.className = c;
    2714 		else
    2715 			// add 時不 detect 是為了速度
    2716 			element.className += ' ' + c;
    2717
    2718 		if ((flag & 2) != 2)
    2719 			return;
    2720 	}
    2721
    2722 	//sl('set_class: remove [' + class_name + '] from [' + o.className + ']');
    2723 	c = element.className.split(/\s+/);
    2724 	var r = {}, i;
    2725
    2726 	for (i in c)
    2727 		r[c[i]] = 1;
    2728
    2729 	if (remove && class_name) {
    2730 		if (!(class_name instanceof Array))
    2731 			class_name = [ class_name ];
    2732 		for (i in class_name) {
    2733 			c = class_name[i];
    2734 			if (c in r) {
    2735 				// has removed
    2736 				remove = 0;
    2737 				delete r[c];
    2738 			}
    2739 		}
    2740 		if (!remove) {
    2741 			c = [];
    2742 			for (i in r)
    2743 				c.push(i);
    2744 			element.className = c.join(' ');
    2745 		}
    2746 	}
    2747
    2748 	//sl('set_class: → ['+o.className+']');
    2749 	return r;
    2750 };
    2751
    2752 //	if cN instanceof RegExp, cN should has NO global flag.
    2753 CeL.interact.DOM
    2754 .
    2755 /**
    2756  * If HTML element has specified class
    2757  * @param {HTMLElement} element	HTML elements
    2758  * @param {String} class_name	class_name_1[ class_name_2 ..]
    2759  * @return	{Boolean}
    2760  */
    2761 has_class = function(element, class_name) {
    2762 	var _s = _.has_class, n = element.className, i;
    2763 	//class_name = class_name.replace(/\s+$|^\s+/g, '');
    2764 	if (!n || !class_name)
    2765 		return;
    2766
    2767 	if (class_name instanceof Array) {
    2768 		for (i = n = 0; i < class_name.length; i++)
    2769 			if (_s(element, class_name[i]))
    2770 				n++;
    2771 		return n;
    2772 	}
    2773
    2774 	if (class_name instanceof RegExp)
    2775 		return class_name.test(n);
    2776
    2777 	if (n === class_name)
    2778 		return true;
    2779
    2780 	//return (new RegExp('(^|\\s)' + class_name + '(\\s|$)'/* ,i */)).test(n);
    2781 	return (' '+n+' ').indexOf(' ' + class_name + ' ')!==-1;
    2782 };
    2783
    2784
    2785 CeL.interact.DOM
    2786 .
    2787 /**
    2788  * @param {String} class_name	class_name_1[ class_name_2 ..]
    2789  * @param {HTMLElement} element	HTML elements
    2790  * @param {HTMLElement} parent_node	parent node
    2791  * @param {String} tag_name	tag name
    2792  * @return	{[HTMLElement]}	nodes
    2793  * @see
    2794  * document.getElementsByClassName in prototype.js,
    2795  * jquery('.class')
    2796  *
    2797  * document.querySelector()
    2798  * http://www.w3.org/TR/selectors-api/
    2799  * http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/04/17/document-queryselector-in-ie8.aspx
    2800  */
    2801 find_class = function(class_name, parent_node, tag_name, call_function,
    2802 		flag) {
    2803 	var elements = class_name
    2804 			&& (parent_node || document).getElementsByTagName(tag_name || '*'), l = elements
    2805 			&& elements.length;
    2806
    2807 	if (l) {
    2808 		var i = 0, c = [], r = new RegExp('(^|\\s)' + class_name + '(\\s|$)'/* ,i */);
    2809 		for (; i < l; i++)
    2810 			if (r.test(elements[i].className)/* has_class(elements, r) */
    2811 					&& (!call_function || call_function.call(elements[i])))
    2812 				c.push(elements[i]);
    2813 		return c;
    2814 	}
    2815
    2816 	return null;
    2817 };
    2818
    2819
    2820
    2821
    2822
    2823 /*	處理 popup 用
    2824 	對className的tag作popup處理
    2825 	window.onload="dealPopup()";
    2826 	<b title="注釋">正文</b>
    2827 */
    2828 //dealPopup[generateCode.dLK]='sPop,has_class';
    2829 function dealPopup(tag,classN,func){
    2830 	if (!tag)
    2831 		tag = 'b';
    2832
    2833 /*
    2834 	http://enable.nat.gov.tw/document/4_2.jsp
    2835 	http://ccca.nctu.edu.tw/~hlb/tavi/ABBRorACRONYM
    2836 	應該用abbr(abbreviation/abbrevitated form/簡稱)
    2837 	abbr包含acronym(頭文字/首字母縮寫,通常這個字的發音像一個字)
    2838 	根據W3C的規範說，中日文的縮寫格式要套用的是abbr標籤。
    2839 	XHTML2.0把acronym移掉了，只剩下abbr標籤。
    2840 	http://www.sovavsiti.cz/css/abbr.html
    2841 	if(!!document.all)document.body.innerHTML=document.body.innerHTML.replace(/<\s*(\/?)\s*abbr([>\s])/gi,'<$1span$2');
    2842 */
    2843
    2844 	var i, j, o = document.getElementsByTagName(tag), tp;
    2845 	dealPopup.list=[];
    2846 	if(o.length)for(i=0;i<o.length;i++){
    2847 		if (classN && !has_class(o[i], classN) || func
    2848 				&& func(o[i]))
    2849 			continue;
    2850 		//	測試是否有特定標籤
    2851 		for (j = 0, tp = ''; j < sPopP.allTypes.length; j++)
    2852 			if (o[i][sPopP.allTypes[j]]) {
    2853 				tp = sPopP.allTypes[j];
    2854 				break;
    2855 			}
    2856 		//	有的話設定event
    2857 		if( tp && (tp=sPop(o[i],sPopF[tp]|sPopF.nopop)) ){
    2858 			//o[i].innerHTML+='<b style="color:peru">['+sPopP.types[tp]+']<\/b>';
    2859
    2860 			dealPopup.list.push(o[i]);
    2861 			if(tp==sPopF.window){
    2862 				if(!o[i].onclick)o[i].onclick=new Function('sPop(this,'+tp+');'),o[i].style.cursor='pointer';
    2863 			}else if(tp==sPopF.popup){
    2864 				if(!o[i].onmouseover){//o[i].ruby=o[i].popup='',
    2865 					o[i].onmouseover=new Function('sPop(this,'+tp+');');
    2866 					if(!o[i].onmouseout)o[i].onmouseout=new Function('sPop(this,sPopF.clearPop);');
    2867 					if(!o[i].onclick)o[i].onclick=new Function('this.onmouseout=null;sPop(this,'+tp+');'),o[i].style.cursor='pointer';
    2868 				}
    2869 				//else alert(tp+'\n'+sPopF[tp]+'\n'+typeof o[i].onmouseover+'\n'+o[i].onmouseover);
    2870 			}
    2871 		}
    2872 	}
    2873 }
    2874 /*	注釋(reference) / show popup-window or ruby	2004/4/3 17:20
    2875 	http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K742.aspx
    2876
    2877 example:
    2878 	<b onmouseover="sPop(this,sPopF._type_,'注釋')">txt</b>
    2879 	<b onmouseover="sPop(this,sPopF._type_)" title="注釋">txt</b>
    2880 	window.onload="dealPopup()"; + <b title="注釋">txt</b>,<b sPop="注釋">txt</b>
    2881 	<b onmouseover="sPop('．',this)">txt</b>	在每個字旁邊加上[．]或[。]
    2882 	sPop('txt')	popup txt(自動設成sPopF.popup)
    2883 	sPop('txt',sPopF.window)	popup txt by window
    2884
    2885 flag & type:
    2886 	sPopF.title/sPopF.auto	（依字數）自動選取
    2887 	sPopF.ruby	採用<ruby>
    2888 	sPopF.popup	採用popup window
    2889 	sPopF.window	將資料開在新視窗
    2890
    2891 	sPopF.nopop	just test, don't popup(for ruby)
    2892 	sPopF.repeat	repeat ruby
    2893 	sPopF.clearPop	clear popup window
    2894 	sPopF.force	若是不能使用此種表示方法，則放棄顯示。(for popup @ Mozilla)
    2895
    2896 style class application(應用):
    2897 	sPopP.DclassName中所定之className為觸發事件時會設定的class
    2898
    2899 執行環境environment:
    2900 	JScript @ HTML
    2901
    2902 include function:
    2903 	String.x()
    2904 	parseFunction()
    2905 	setObjValue()
    2906
    2907 TODO:
    2908 submenu
    2909 	http://dynamicdrive.com/dynamicindex1/popupmenu.htm
    2910 Tipped - The Javascript Tooltip Framework
    2911 	http://projects.nickstakenburg.com/tipped
    2912
    2913 How to Create a Valid Non-Javascript Lightbox | Carsonified
    2914 http://carsonified.com/blog/design/css/how-to-create-a-valid-non-javascript-lightbox/
    2915
    2916 move/resize/最小化: popup dialog
    2917 	http://deluxepopupwindow.com/html-popup-dialog-vista-graphite.html
    2918
    2919 獨佔 window, 訊息列, 多功能(HTML+Script)內容
    2920 	http://vision-media.ca/resources/jquery/jquery-popup-plugin-review
    2921
    2922 key (Esc)
    2923 time limit
    2924
    2925 */
    2926 var sPopP={}	//	sPop properties object
    2927 	,sPopF	//	flag
    2928 	,sPopError//	for error
    2929 	;
    2930
    2931 //	初始值設定 & 設定flag
    2932 //if(sPopP)alert('sPopP 已被佔用！');else
    2933 function sPopInit(){
    2934
    2935 	//	預設style class name:(null:used last time),ruby,popup,window
    2936 	sPopP.DclassName=',popupedTxt_ruby,popupedTxt,popupedTxt'.split(',');
    2937 	//	已登記的背景style,請在CSS中加入[sPopC]_[body class name]
    2938 	sPopP.bgS='bgb,bgn';
    2939 {
    2940  var i=0,t=sPopP.bgS.split(',');sPopP.bgS={};
    2941  for(;i<t.length;i++)sPopP.bgS[t[i]]=i+1;
    2942 }
    2943 	//	popup window style
    2944 	sPopP.popupS="color:blue;padding:.5em;overflow:auto;position:absolute;top:0;left:0;width:100%;height:100%;scrollbar-face-color:khaki;scrollbar-arrow-color:teal;border:1px solid green;font:normal 10pt tahoma;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#ffd700, EndColorStr=#ffffff);";
    2945 	//	chars to repeat(for ruby)
    2946 	sPopP.RepeatC='‧．。ヽ○●◎☆★※＊＃▽▼△▲◆◇□■↓↑';//.turnU();
    2947 	//	types:auto,這些attribute可被處理，且將被視為自動選取type。
    2948 	sPopP.autoTypes='title,_sPop';//+',_'+sPopP.functionName
    2949 	//	types,最多七種
    2950 	sPopP.types='ruby,popup,window';	//	+div(參考dealLinkPopup())
    2951 	//	所有可用的types，可用來detect是否能為sPop()所接受。但Mozilla中無法使用title之外的attribute。
    2952 	sPopP.allTypes=(sPopP.autoTypes+','+sPopP.types).split(',');
    2953 	//	function name
    2954 	sPopP.functionName='';//;parseFunction().funcName;
    2955 	//	popup window(for popup)
    2956 	if(typeof window.createPopup!='undefined')sPopP.window=window.createPopup();
    2957 {
    2958  var i=0,t=sPopP.types.split(','),T='';
    2959  for(;i<t.length;)T+=t[i]+'='+ ++i+',';//alert(T);
    2960  setObjValue('sPopF','title=0,auto=0,'
    2961 	//+'_'+sPopP.functionName+'=0,'
    2962 	+T+'nopop=8,repeat=16,clearPop=32,force=64','int');
    2963 }
    2964 //	sPopP.types[index]=type name
    2965 sPopP.types=(
    2966 	//'_'+sPopP.functionName+
    2967 	','+sPopP.types).split(',');
    2968 sPopP.commentTitle='Comment';	//	註解
    2969 sPopP.commentTitlePattern=sPopP.commentTitle+' of %s';
    2970 sPopP.closeM='Close';	//	close message: 關閉視窗或popup
    2971 sPopP.biggerM='Bigger';	//	bigger message: 放大
    2972 sPopP.resetM='Reset size';	//	reset size message: 回復原大小
    2973 }
    2974
    2975 //	主object(正文或主object，會從之取得正文與注釋)[, flag, text string or object(注釋,會蓋過從主object取得之text), 使用的class name]
    2976 //sPop[generateCode.dLK]='sPopP,sPopF,sPopInit,*sPopInit();';
    2977 function sPop(oPos,flag,oTxt,classN){
    2978  //if(flag&sPopF.clearPop){if(sPopP.window)sPopP.window.hide();return;}
    2979
    2980  //	input value test & 修正
    2981  if(!oPos&&!oTxt)return;
    2982
    2983  var limitW=screen.width-50,limitH=screen.height>>1;
    2984  if(!sPopP.width)sPopP.width=250;if(sPopP.width>limitW)sPopP.width=limitW;
    2985  if(!sPopP.height)sPopP.height=100;if(sPopP.height>limitH)sPopP.height=limitH;
    2986
    2987  //	初始值設定
    2988  if(!sPopP.functionName)
    2989   sPopF[ sPopP.types[0]='_'+(sPopP.functionName=parseFunction().funcName) ]=0;
    2990
    2991  var repopMark='repop',repop=oPos===repopMark,nopop=flag&sPopF.nopop,tp=flag&7
    2992 	,useAttbTxt=false,brReg=/\r*\n/g,brT='<br/>\n';	//	轉成br用
    2993
    2994 if(repop){
    2995   if( !sPopP.popObj || typeof sPopP.popObj!='object' || typeof sPopP.popObj.innerHTML!='string' || !sPopP.popObj.innerHTML )return;
    2996   oPos=sPopP.popObj,tp=sPopF.popup;	//	重pop時不作其他判別處置
    2997 }else{
    2998
    2999  //	處理object
    3000  if( typeof oPos=='string' && oPos )
    3001   if( oPos.length<32 && document.getElementById(oPos) )
    3002    oPos=document.getElementById(oPos);	//	輸入object name時轉成object
    3003   else if(!oTxt)oTxt=oPos	//	若只輸入oPos，將之當作注釋(oTxt)。
    3004 	//,oPos=typeof null=='object'?0:null;
    3005 	,oPos=0;	//	若是typeof null=='object',請設成false
    3006
    3007  //	設定oTxt 1/4
    3008  if( typeof oTxt=='object' && oTxt.innerHTML )oTxt=oTxt.innerHTML;
    3009  else if(oTxt)oTxt+='';	//	轉成string
    3010
    3011  //	(自動)判別使用的type
    3012  var useAutoTxt;
    3013  if(tp==sPopF.auto){
    3014   //	設定oTxt 2/4 : 知道是自動判別後先設定
    3015   if( typeof oPos=='object' && (!oTxt||oTxt==0) )
    3016    if(oPos[sPopP.types[0]])oTxt=oPos[sPopP.types[0]],useAutoTxt=true;
    3017    else if(oPos.title)oTxt=oPos.title,useAutoTxt=true;	//	以<b title="~">的用法來說，這是最常經過的path
    3018
    3019   //	假如沒有oTxt.gText()，改成oTxt.replace(/<[^>]*>/g,'')之即可。這是為了預防HTML的情形。
    3020   var len=typeof oTxt=='string'?oTxt.length:0;//typeof oTxt=='string'?oTxt.length:typeof oTxt=='object'&&oTxt.innerHTML?oTxt.innerHTML.length:0;
    3021   //alert(len+','+(len*.7)+','+oPos.innerHTML.length);
    3022   if( typeof oPos=='object' && ( oPos.doneRuby || !oPos.innerHTML.match(/<\s*ruby/i) && (len<60&&len*.7-9<(typeof oPos.innerText=='string'?oPos.innerText:oPos.innerHTML).length) ) )
    3023    tp='ruby';	//	ruby的條件
    3024   else if(sPopP.window&&len<300){
    3025    tp='popup';
    3026    if(typeof oPos=='object'&&oPos.title===oTxt)oPos[sPopP.types[0]]=oTxt,oPos.title='';
    3027   }else tp='window';
    3028
    3029   //	設定oTxt 3/4 & type
    3030   if( typeof oPos=='object' && (!oTxt||oTxt==0) )
    3031    if(oPos[tp])oTxt=oPos[tp],useAutoTxt=true;
    3032
    3033   tp=sPopF[tp];
    3034  }
    3035
    3036  //	設定oTxt 4/4
    3037  if( !oTxt||oTxt==0 && typeof oPos!='object')
    3038   if( (oTxt=oPos[sPopP.types[tp]]) || (oTxt=oPos[sPopP.types[0]]) || (oTxt=oPos.title) )useAutoTxt=true;else return;
    3039
    3040  //	設定className與position
    3041  sPopP.left=0,sPopP.top=20;	//	popup left,popup top初始值
    3042  if( !oPos || typeof oPos!='object')
    3043   //	popup 在滑鼠指標處
    3044   //	see: add_listener()
    3045   try{sPopP.left+=event.offsetX,sPopP.top+=event.offsetY;}catch(e){}
    3046  else if( !oPos.className && sPopP.DclassName[tp] ){
    3047   if(!classN&&(classN=document.body.className)&&!sPopP.bgS[classN])classN=0;
    3048   oPos.className=sPopP.DclassName[tp]+(classN?'_'+classN:'');
    3049   var w,s=oPos.style;if(!s.fontWeight&&(w=oPos.parentNode.style.fontWeight))s.fontWeight=w;	//	除非有明確設定font-weight，否則通常不會有效
    3050  }
    3051 }
    3052
    3053  //	修正
    3054  if( tp==sPopF.popup && !sPopP.window && !(flag&sPopF.force) )
    3055   tp=sPopF.window;	//	Mozilla中無法顯示popup
    3056
    3057
    3058  //alert(sPopP.types[tp]+','+( sPopP.window || flag&sPopF.force )+','+oTxt);
    3059  //	處理pop
    3060  if(tp==sPopF.ruby){
    3061   if(typeof oPos!='object'||!oPos.innerHTML)return;	//	oPop非HTML element就return
    3062   if(oPos.doneRuby)return tp;	//	已經處理過<ruby>就pass
    3063   //	處理repeat
    3064   if( flag&sPopF.repeat || sPopP.RepeatC.indexOf(oTxt)!=-1 )
    3065    oPos.title='',oTxt=window.navigator.userAgent.indexOf("MSIE")<0?'':oTxt.x(oPos.innerHTML.length/oTxt.length);	//	只有IE提供ruby，所以這時候不宜加入旁點功能。
    3066
    3067   try{
    3068    oPos.innerHTML='<ruby><rb>'+oPos.innerHTML+'<\/rb><rp>'
    3069 	//	半形與全形的括弧
    3070 	+(oTxt?window.navigator.userAgent.indexOf("Opera")>=0||/^[a-z\d\s_,.;"'\[\]{}+\-*\/]*$/i.test(oTxt)?'(<\/rp><rt>'+oTxt+'<\/rt><rp>)':'（<\/rp><rt>'+oTxt+'<\/rt><rp>）':'<\/rp><rt><\/rt><rp>')
    3071 	+'<\/rp><\/ruby>';
    3072   }catch(e){
    3073    var n=e.number&0xFFFF;
    3074    if(n==601&&(typeof sPopError=='undefined'||sPopError!=n))alert('Error: '+e.description+' at\n'+oPos.outerHTML+'\n\n★也許是在這之前的tag出錯，例如有<b>卻沒有<\/b>。');
    3075    sPopError=n;
    3076   }
    3077   oPos.doneRuby=true;
    3078
    3079  }else if(tp==sPopF.popup){
    3080   if(nopop||!sPopP.window)return tp;
    3081   if(!repop){
    3082    if(useAutoTxt)oTxt=oTxt.replace(brReg,brT);
    3083    //	這是一種註解功能，在mouseout後，假定讀者繼續讀下去，所以就讓popup object消失。想要多看一點的，會去按他，這時才讓popup object繼續存在。
    3084    sPopP.window.document.body.innerHTML=//oTxt=
    3085 	'<div style="'+sPopP.popupS+'" onblur="parent.sPopP.window.hide();" title="reference">[<b style="color:peru;cursor:pointer;" onclick="parent.sPopP.window.hide();">'+sPopP.closeMessage+'<\/b>] [<b style="color:green;cursor:pointer;" onclick="with(parent)sPopP.width+=100,sPopP.height+=50,'
    3086 	+sPopP.functionName+'(\''+repopMark+'\');">'+sPopP.biggerM+'<\/b>] [<b style="color:orange;cursor:pointer;" onclick="with(parent)sPopP.width=sPopP.height=0,'+sPopP.functionName+'(\''+repopMark+'\');">'+sPopP.resetM+'<\/b>]<hr style="color:purple;height:1px"/>'+oTxt.replace(/'/g,''')+'<\/div>';
    3087    sPopP.popObj=oPos||document.body;	//	object deal now(for popup:repop)
    3088    //if(typeof oPos.onmouseout!='undefined')oPos.onmouseout=function(){sPopP.window.hide();};
    3089   }
    3090   //alert(sPopP.width+','+sPopP.height);
    3091   if(flag&sPopF.clearPop)sPopP.window.hide();
    3092   else sPopP.window.show(sPopP.left,sPopP.top,sPopP.width,sPopP.height,oPos||document.body);
    3093
    3094  }else if(tp==sPopF.window){
    3095   if(nopop)return tp;
    3096   //if(typeof netscape=='object')netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");	//	創造無邊框視窗:titlebar=no	dependent:ns only	全螢幕：channelmode	带有收藏链接工具栏的窗口：directories	网页对话框：'dialogWidth:400px;dialogHeight:300px;dialogLeft:200px;dialogTop:150px;center:yes;help:yes;resizable:yes;status:yes'
    3097 /*
    3098 dialogHeight: iHeight 设置对话框窗口的高度。
    3099 dialogWidth: iWidth 设置对话框窗口的宽度。
    3100 dialogLeft: iXPos 设置对话框窗口相对于桌面左上角的left位置。
    3101 dialogTop: iYPos 设置对话框窗口相对于桌面左上角的top位置。
    3102 center: {yes | no | 1 | 0 } 指定是否将对话框在桌面上居中，默认值是“yes”。
    3103 help: {yes | no | 1 | 0 } 指定对话框窗口中是否显示上下文敏感的帮助图标。默认值是“yes”。
    3104 resizable: {yes | no | 1 | 0 } 指定是否对话框窗口大小可变。默认值是“no”。
    3105 status: {yes | no | 1 | 0 } 指定对话框窗口是否显示状态栏。对于非模式对话框窗口，默认值是“yes”；对于模式对话框窗口，默认值是 “no”。
    3106
    3107 window.showModalDialog(), window.showModelessDialog(): IE only. 不如用Ajax
    3108 */
    3109   var w=window.open('','comment','titlebar=no,dependent,resizable=1,menubar=0,toolbar=0,location=0,scrollbars=1,width=550,height=400'/*,fullscreen*/,false)
    3110 	,t=sPopP.commentTitle,_t=oPos.innerHTML&&oPos.innerHTML.length<9?sPopP.commentTitlePattern.replace(/%s/,oPos.innerHTML):t;	//	head, document.title
    3111   //if(typeof netscape=='object')netscape.security.PrivilegeManager.disablePrivilege("UniversalBrowserWrite");
    3112   if(document.title)t+=' @ ['+document.title+']',_t+=' @ '+document.title;
    3113   //else t+=' @ [<a href="'+location.href+'">'+location.pathname+'<\/a>]';
    3114   with(w.document)open(),
    3115    write(
    3116 	//'<?xml version="1.1" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="content-type" content="text/html;charset=utf-8"/><title>'
    3117 	//+_t+'<\/title><script type="text/javascript">window.onblur=function(){window.close();};<\/script><\/head><body><b style="color:#11f;">'+t+':<\/b>'
    3118 	'<script type="text/javascript">window.onblur=function(){window.close();};<\/script><b style="color:#11f;">'+t+':<\/b>'
    3119 	+(oPos.innerHTML?'<div id="s" style="color:#488;background-color:#FF8;">\n'+oPos.innerHTML.replace(/\n/g,'<br/>').replace(/ /g,' ')+'\n<\/div><hr/>':'')	//;white-space:normal;width:500px:useless	** 這邊會對<b title="..等造成影響！
    3120 	+'<div id="c" style="color:#404;background-color:#8FF;">\n'+oTxt.replace(/\n/g,'<br/>').replace(/ /g,' ')	//	以不換行(pre)的方式顯示.patch
    3121 	+'\n<\/div><hr/>[ <b style="cursor:pointer;color:#40f;" onclick="javascript:opener.focus();self.close();">'+sPopP.closeMessage+'<\/b> ]')//+'</body></html>'
    3122    ,close(),title=_t;
    3123   w.focus();
    3124   w=0;	//	open出來的窗口即使close了，它的window對象還是存在的，要記得刪除引用	http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html
    3125  }//else alert('type error: '+tp+'!');
    3126
    3127  return tp;	//	回傳決定的type
    3128 }
    3129
    3130
    3131 /*	開啟連結於 target
    3132 	**	最好將openAtInit();設在onload
    3133 	JScript solution for attribute 'target' @ XHTML1.1	<a target="tag">之取代策略
    3134 	way 1:	,captureE,openAtInit,"openAtInit();",openAt
    3135 	onload: + openAtInit()		,captureE,openAtInit,"openAtInit();",openAt
    3136 	target="tag"	→	onclick="return openAt('tag')"
    3137 	target="_blank"	→	onclick="return openAt()"
    3138 	target="_self"	→	onclick="return openAt(1)"
    3139 	way 2:	,openAt
    3140 	target="_blank"	→	onclick="return openAt(0,this.href)"
    3141 	target="_self"	→	onclick="return openAt(1,this.href)"
    3142 	http://tohoho.wakusei.ne.jp/js/event.htm
    3143
    3144 TODO:
    3145 http://hi.baidu.com/monyer/blog/item/56f1c88095fc96d79023d931.html
    3146 a{text:expr/*XSS* /ession(target="_blank");}
    3147
    3148 http://blog.fanstown.net/blogs/jerry/archive/2007/04/04/HTML_8476_rel_5E5C2760E68BE3890230_.aspx
    3149 原來這樣寫的代碼：
    3150 <a href="document.html" target="_blank"> 打開一個新窗口</a>
    3151 現在要寫成這樣：
    3152 <a href="document.html" rel="external">打開一個新窗口</a>
    3153 這是符合strict標準的方法。當然還必須配合一個javascript才有效。
    3154 **	應該 binding a.onclick 或 a.keypress
    3155 rel是relationship的英文縮寫.rel與rev具有互補的作用,rel指定了向前鏈接的關係,rev指定了反向鏈接的關係.
    3156
    3157 */
    3158 var captureE;
    3159 //	初始化設定
    3160 //openAtInit[generateCode.dLK]='captureE';
    3161 function openAtInit(){
    3162  if(typeof captureE!='object'&&(typeof Event=='object'||typeof Event=='function')){	//	for moz
    3163   //	http://developer.mozilla.org/en/docs/DOM:element.addEventListener	http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event
    3164   if(Event.mousedown)window.captureEvents(Event.mousedown);
    3165   if(Event.keydown)window.captureEvents(Event.keydown);
    3166   window.onmousedown=window.onkeydown=function(e){
    3167 	 captureE=e;//alert('openAtInit: '+e.target.tagName);
    3168 	};
    3169  }
    3170  for(var i,a=document.getElementsByTagName('a');i<a.length;i++)
    3171   if(a[i].onclick&&!a[i].onkeypress&&(''+a[i].onclick).indexOf('openAt')!=-1)a[i].onkeypress=a[i].onclick;
    3172 }
    3173 //	open h(ref) in tag(et)
    3174 //openAt[generateCode.dLK]='captureE,openAtInit';
    3175 function openAt(tag,h){
    3176  if(!tag)tag='_blank';//typeof tag=='undefined'||
    3177  else if(tag===1)tag='_self';
    3178  var t;
    3179  if(!h&&typeof event=='object')h=event.srcElement.href;
    3180
    3181  //	對Gecko等使用標準(?)Document Object Model的
    3182  //	http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
    3183  if(!h&&typeof captureE=='object'&&typeof captureE.target=='object'){
    3184   t=captureE.target;
    3185   while(!(h=t.href)&&(t=t.parentNode));
    3186  }
    3187
    3188  //alert(h+','+tag+'\n'+captureE.target.parentNode.tagName+":");//+captureE.target.parentElement().tagName
    3189  if(h)window.open(h,tag).focus();
    3190  return false;
    3191 }
    3192
    3193 /*	display mark to valid document
    3194 	<div id="valid"> </div>
    3195 	window.onload="addValid()";
    3196 	搞定之後把自己網站提交到W3C Sites收錄。	http://www.w3csites.com/
    3197
    3198 	for RSS:
    3199 	http://rss.scripting.com/?url=http%3A%2F%2Flyrics.meicho.com.tw%2Fgame%2Frss.xml
    3200 	http://feedvalidator.org/check.cgi?url=http%3A%2F%2Flyrics.meicho.com.tw%2Fgame%2Frss.xml
    3201 */
    3202 function addValid(v,tf){	//	object to insert valid, target window/frame
    3203  if(location.protocol=='file:')return;
    3204  if(!v)v='valid';if(typeof v!='object')v=document.getElementById(v);
    3205  if(!v)return 1;if(v.innerHTML.replace(/ /g,'').replace(/\s+/g,''))return 2;
    3206
    3207  if(typeof tf==='undefined')tf='valid_window';//tf=dQuote(tf);//tf?' target="'+tf+'"':'';
    3208  var i=0,t='',d,addValidData=[
    3209 	'Valid XHTML 1.1! by W3C	http://validator.w3.org/check?uri=referer	http://www.w3.org/Icons/valid-xhtml11'
    3210 	//,'Valid XML 1.0! by W3C	'
    3211 	,'Valid CSS! by W3C	http://jigsaw.w3.org/css-validator/check/referer	http://jigsaw.w3.org/css-validator/images/vcss'	//	http://jigsaw.w3.org/css-validator/validator?uri=~
    3212 	,'Validome Validation Services	http://www.validome.org/referer	http://www.validome.org/images/valid/set2/valid_xhtml_1_1.png'
    3213 	,'Another HTML-lint check	http://openlab.ring.gr.jp/k16/htmllint/htmllint.cgi?ViewSource=o	http://openlab.ring.gr.jp/k16/images/ahl-blue.gif'
    3214 	,'Bobby WAI-AAA Approved by bobby@watchfire.com	http://bobby.watchfire.com/bobby/bobbyServlet?URL=~&output=Submit&gl=wcag1-aaa	http://bobby.watchfire.com/bobby/html/en/images/approved_aaa.gif'
    3215 	,'Bobby 508 Approved by bobby@watchfire.com	http://bobby.watchfire.com/bobby/bobbyServlet?URL=~&output=Submit&gl=sec508	http://bobby.watchfire.com/bobby/html/en/images/approved_508.gif'
    3216 	//	http://webxact.watchfire.com/
    3217 	];
    3218  for(;i<addValidData.length;i++)
    3219   if(d=addValidData[i].split('	'),d[1])t+=' <a title="'+d[0]+'" href="'+d[1].replace(/~/g,encodeURI(location.href))
    3220 	+'" target="'+tf+'">'
    3221 	+(d[2]?'<img style="display:inline;width:88px;" alt="'//'" onclick="return openAt(\''+tf+'\');"><img style="display:inline;" alt="'	IE不通
    3222 		+d[0]+'" src="'+d[2]+'"/>':d[0])
    3223 	+'<\/a>';	//	tf.focus()
    3224   else alert('Validate data defined error!');
    3225  v.innerHTML='Validate this document:<br/>'+t;
    3226  v.style.display='block';
    3227  return t;
    3228 }
    3229
    3230
    3231 /*	延遲執行: 加強版的 setTimeout?
    3232
    3233 id=delayRun(function[,ms=0])
    3234
    3235 id=delayRun([function,[args],this] [,ms=0])
    3236
    3237 */
    3238 function delayRun(f,ms){
    3239  var _f=delayRun,i;
    3240  if(!_f.fL)_f.fL=[];
    3241  i=_f.fL.length;
    3242  _f.fL.push(f);
    3243  setTimeout('delayRun.run('+i+');',ms||0);
    3244  return i;
    3245 }
    3246 delayRun.clear=function(i){
    3247  //	clearTimeout(): 為求簡單省略
    3248  delete this.fL[i];
    3249 };
    3250 delayRun.run=function(i){
    3251  var _t=this,f=_t.fL[i];
    3252  if(f){
    3253   if(typeof f=='function')f();
    3254   else if(f instanceof Array)f[0].apply(f[2]||null,f[1]);
    3255   else eval(f);
    3256   delete _t.fL[i];
    3257  }
    3258 };
    3259
    3260
    3261
    3262
    3263
    3264
    3265
    3266 /*	MsgBox, InputBox Titlebars Prefixed with 'VBScript'	http://support.microsoft.com/default.aspx?scid=kb;en-us;234742
    3267 	http://asp.programmershelp.co.uk/vbscriptmsgbox.php
    3268 	http://17.webmasters.com/caspdoc/html/vbscript_msgbox_function.htm
    3269 請加入下面一段中介function
    3270 <script type="text/vbscript">
    3271 Function VBalert_vbf()
    3272  VBalert_f.ret=MsgBox(VBalert_f.prompt,VBalert_f.buttons,VBalert_f.title,VBalert_f.helpfile,VBalert_f.context)
    3273 End Function
    3274 </script>
    3275
    3276 or use:
    3277 window.execScript( sExpression, sLanguage );
    3278 */
    3279 //var VBalert_f;VBalert();	//	init
    3280 function VBalert(prompt,buttons,title,helpfile,context){
    3281  if(typeof VBalert_f!='object')VBalert_f={},setObjValue('VBalert_f','ret=0,'
    3282 	//	http://msdn.microsoft.com/library/en-us/script56/html/vsfctmsgbox.asp
    3283 	+'vbOK=1,vbCancel=2,vbAbort=3,vbRetry=4,vbIgnore=5,vbYes=6,vbNo=7,'
    3284 	+'vbOKOnly=0,vbOKCancel=1,vbAbortRetryIgnore=2,vbYesNoCancel=3,vbYesNo=4,vbRetryCancel=5,'
    3285 	+'vbCritical=16,'	//	Critical Message icon	(x)
    3286 	+'vbQuestion=32,'	//	Warning Query icon	(?)
    3287 	+'vbExclamation=48,'	//	Warning Message icon	(!)
    3288 	+'vbInformation=64,'	//	Information Message icon(i)
    3289 	+'vbDefaultButton1=0,vbDefaultButton2=256,vbDefaultButton3=512,vbDefaultButton4=768,vbApplicationModal=0,vbSystemModal=4096','int');
    3290  if(typeof prompt=='undefined')return;
    3291  VBalert_f.prompt=prompt||'',VBalert_f.buttons=buttons||0,VBalert_f.title=title||'';
    3292  //	Not available on 16-bit platforms.	http://msdn.microsoft.com/library/en-us/script56/html/vsfctmsgbox.asp
    3293  VBalert_f.helpfile=helpfile||'',VBalert_f.context=context||0;
    3294  try{
    3295   VBScript:VBalert_vbf();
    3296   return VBalert_f.ret;
    3297  }catch(e){
    3298   //alert('VBalert error:'+e.message);
    3299   alert(VBalert_f.prompt);
    3300  }
    3301 }
    3302 //alert(VBalert('12',VBalert_f.vbInformation+VBalert_f.vbDefaultButton3));
    3303
    3304
    3305
    3306 /*	get window status	取得視窗可利用的size。現在還得用種方法，真是羞恥。	2005/1/13 20:0
    3307 	get_window_status(event object)
    3308 	http://www.mozilla.org/docs/dom/domref/dom_window_ref.html
    3309 	http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/body.asp
    3310 	http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=16
    3311 	http://www.webdevtips.com/webdevtips/faq/javascript/index.shtml
    3312 	http://www.quirksmode.org/viewport/compatibility.html
    3313 	http://cgi.din.or.jp/~hagi3/JavaScript/JSTips/Mozilla/eventhandle.htm
    3314
    3315 ** untested !!
    3316
    3317 */
    3318
    3319 //var eventObj;
    3320 CeL.interact.DOM
    3321 .
    3322 /**
    3323  * 取得當前 window status
    3324  * @param node	HTML element or Event object
    3325  * @returns {Object}	status
    3326  */
    3327 get_window_status = function (node) {
    3328 	var _s = get_window_status, t = _s.scroll, r = {
    3329 			scrollLeft : t[0],
    3330 			scrollTop : t[1]
    3331 	};
    3332
    3333 	//	能scroll的範圍:不準,yet test	The height of the total page (usually the body element)
    3334 	//	t:test, true:all but Explorer Mac, false:Explorer Mac, would also work in Explorer 6 Strict, Mozilla and Safari
    3335 	var t = typeof document.body.scrollHeight != 'undefined'
    3336 		&& typeof document.body.offsetHeight != 'undefined'
    3337 			&& document.body.scrollHeight > document.body.offsetHeight;
    3338
    3339 	r.scrollW = t ? document.body.scrollWidth
    3340 			: typeof document.body.offsetWidth != 'undefined' ? document.body.offsetWidth
    3341 					: null;
    3342 	r.scrollH = t ? document.body.scrollHeight
    3343 			: typeof document.body.offsetHeight != 'undefined' ? document.body.offsetHeight
    3344 					: null;
    3345
    3346 	// window大小
    3347 	// 2009/3/23 1:15:29
    3348 	var NewIE = navigator.appVersion.indexOf("MSIE") != -1
    3349 		&& parseInt(navigator.appVersion.split("MSIE")[1]) > 6;
    3350 	r.windowW = typeof window.innerWidth != 'undefined' ? window.innerWidth
    3351 			: /* typeof offsetWidth!='undefined'?offsetWidth: */!NewIE
    3352 			&& typeof document.body.clientWidth != 'undefined' ? document.body.clientWidth
    3353 					: document.documentElement
    3354 					&& !isNaN(document.documentElement.clientWidth) ? document.documentElement.clientWidth
    3355 							: null;// +offsetLeft
    3356 	r.windowH = typeof window.innerHeight != 'undefined' ? window.innerHeight
    3357 			: /* typeof offsetHeight!='undefined'?offsetHeight: */!NewIE
    3358 			&& typeof document.body.clientHeight != 'undefined' ? document.body.clientHeight
    3359 					: document.documentElement
    3360 					&& !isNaN(document.documentElement.clientHeight) ? document.documentElement.clientHeight
    3361 							: null;// +offsetTop
    3362
    3363 	var noEmu;
    3364 	if (!node)
    3365 		if (typeof window.event === 'object')
    3366 			node = window.event;
    3367 		else if (typeof e === 'object')
    3368 			node = e;
    3369 		else if (typeof eventObj === 'object')
    3370 			noEmu = true, node = eventObj;
    3371
    3372 	if (node) {
    3373 		// Safari: yet test
    3374 		var isSafari = /Safari/i.test(window.navigator.appName);
    3375
    3376 		// window相對於screen位置:不準, yet test
    3377 		r.windowX = node.clientX - ((isSafari) ? r.scrollX : 0);
    3378 		r.windowY = node.clientY - ((isSafari) ? r.scrollY : 0);
    3379 		// mouse位置
    3380 		// http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_event.asp
    3381 		// http://www.mozilla.org/docs/dom/domref/dom_event_ref.html
    3382 		r.mouseX = node.clientX + ((!isSafari) ? r.scrollX : 0);
    3383 		r.mouseY = node.clientY + ((!isSafari) ? r.scrollY : 0);
    3384 		if (!noEmu)
    3385 			//	模擬event obj，因為event obj不能在event發生時之function執行完後再取得
    3386 			eventObj = {
    3387 					'clientX' : node.clientX,
    3388 					'clientY' : node.clientY
    3389 			};
    3390 			// alert(r.scrollX+','+r.scrollY+'\n'+o.clientX+','+o.clientY);
    3391 	}
    3392
    3393 	return r;
    3394 };
    3395
    3396 CeL.interact.DOM
    3397 .
    3398 //	IE7遵照標準，不用 document.body.scrollLeft 而用 document.documentElement.scrollLeft
    3399 //	http://hkom.blog1.fc2.com/blog-entry-423.html
    3400 //	http://diaspar.jp/node/47
    3401 get_window_status.scroll = function (node) {
    3402 	var box_model, od = node && node.ownerDocument;
    3403
    3404 	try{
    3405 		//	from jQuery
    3406 		var div = document.createElement('div');
    3407 		div.style.width = div.style.paddingLeft = '1px';
    3408
    3409 		document.body.appendChild(div);
    3410 		_.get_window_status.box_model = box_model = div.offsetWidth === 2;
    3411 		if(!node)
    3412 			od = div.ownerDocument;
    3413 		document.body.removeChild(div).style.display = 'none';
    3414
    3415 		div = null;
    3416
    3417 	}catch (e) {
    3418 		// TODO: handle exception
    3419 	}
    3420
    3421 	//	到這邊，若是 od 未設定，則所有取值與 node 無關。
    3422 	//	因為大多有 ownerDocument，所以預設編入。
    3423 	//	新的 browser，od 與 dv 皆應有設定。
    3424
    3425 /*
    3426
    3427 Firefox/3.6.6: ownerDocument: [object HTMLDocument], defaultView: [object Window], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0
    3428 Chrome/6.0.453.1 Safari/534.2: ownerDocument: [object HTMLDocument], defaultView: [object DOMWindow], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0
    3429 Safari/533.16: ownerDocument: [object HTMLDocument], defaultView: [object DOMWindow], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0
    3430 Opera/9.80 Presto/2.6.30: ownerDocument: [object HTMLDocument], defaultView: [object Window], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0
    3431
    3432
    3433 MSIE 5.0 @ MSIE 9.0 test: ownerDocument: [object], defaultView: undefined, box_model: false, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined
    3434 MSIE 7.0 @ MSIE 9.0 test: ownerDocument: [object], defaultView: undefined, box_model: true, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined
    3435
    3436 MSIE 8.0: ownerDocument: [object HTMLDocument], defaultView: undefined, box_model: true, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined
    3437 MSIE 9.0 test: ownerDocument: [object HTMLDocument], defaultView: [object Window], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined
    3438
    3439 */
    3440 	//	IE5-8: od: true, dv: false
    3441
    3442 	var doc = node && od || window.document,
    3443 	body = doc.body, dv = doc.defaultView, win = dv || doc.parentWindow;
    3444 	library_namespace.debug('ownerDocument: ' + od + ', defaultView: ' + dv + ', box_model: ' + box_model + ', pageXOffset: ' + win.pageXOffset + ', body.scrollLeft: ' + body.scrollLeft + ', documentElement.scrollLeft: ' + doc.documentElement.scrollLeft + ', scrollX: ' + win.scrollX, 2, 'get_window_status.scroll');
    3445
    3446 	//	** 順序有關係! 但在未設置 box_model 前，body.scrollLeft 排在 documentElement.scrollLeft 前面。現在已按照 jQuery 改過。
    3447 	//	TODO: do test
    3448 	//	[scrollLeft, scrollTop, clientLeft, clientTop]
    3449 	return (_.get_window_status.scroll =
    3450 		!isNaN(win.pageXOffset) ?
    3451 			//	預設 box_model === true
    3452 			function (n) {
    3453 				//	'|| window.document': for Range (see get_selection())
    3454 				var d = n && n.ownerDocument || window.document,
    3455 				w = d.defaultView;
    3456 				d = d.documentElement;
    3457 				return [ w.pageXOffset, w.pageYOffset, d.clientLeft, d.clientTop ];
    3458 			} :
    3459
    3460 		//	IE7(6?)~8
    3461 		box_model && !isNaN(doc.documentElement.scrollLeft) ?
    3462 			function (n) {
    3463 				var d = (n && n.ownerDocument || window.document).documentElement;
    3464 				return [ d.scrollLeft, d.scrollTop, d.clientLeft, d.clientTop ];
    3465 			} :
    3466
    3467 		//	IE5(6?)
    3468 		!isNaN(body.scrollLeft) ?
    3469 			function (n) {
    3470 				var b = (n && n.ownerDocument || window.document).body;
    3471 				return [ b.scrollLeft, b.scrollTop, b.clientLeft, b.clientTop ];
    3472 			} :
    3473
    3474 		!isNaN(win.scrollX) ?
    3475 			//	untested
    3476 			function() {
    3477 				var b = document.body;
    3478 				return [ window.scrollX, window.scrollY, b.clientLeft, b.clientTop ];
    3479 			} :
    3480
    3481 		function() {
    3482 			return [ 0, 0, 0, 0 ];
    3483 		}
    3484 	)(node);
    3485
    3486 };
    3487
    3488
    3489
    3490
    3491
    3492 CeL.interact.DOM
    3493 .
    3494 /**
    3495  * get current computed style property of specified HTML element.
    3496  * TODO: 整合 get_node_offset, _.set_style
    3497  * @param element	HTML element
    3498  * @param name	W3C style property name (e.g., no '-webkit-background-clip')
    3499  * @return
    3500  * @see
    3501  * http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug, http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K983.aspx,
    3502  * curCSS @ jQuery, http://api.jquery.com/category/css/,
    3503  * <a href="http://www.quirksmode.org/dom/getstyles.html" accessdate="2010/4/1 15:44">JavaScript - Get Styles</a>,
    3504  * <a href="http://www.javaeye.com/topic/140784?page=2" accessdate="2010/4/1 15:41">style.display取值不对，难道是浏览器bug？讨论第2页:  - JavaScript - web - JavaEye论坛</a>
    3505  * 大體上，currentStyle 相當於 getComputedStyle，而 runtimeStyle 相當於 getOverrideStyle。但是它們還是有很重要的區別。那就是，IE的CSS計算步驟其實是不合標準的。
    3506  * document.defaultView在mozilla中是指向window obj的,但是很有可能在其他broswer中就不指向window obj...因為w3c中沒有強行規定document.defaultView一定是一個global obj.
    3507  *
    3508  * 返回頁內樣式表定義的類，那麼可以使用DOM樣式表對象來訪問：
    3509  * var oCssRulers = document.styleSheets[0].cssRulers || document.styleSheets[0].rulers;
    3510  * (前者是DOM方法，後者是IE私有方法)
    3511  * alert(oCssRulers[0].style.display);
    3512  * @since	2010/4/2 00:14:09	rewrite
    3513  * @memberOf	CeL.interact.DOM
    3514  */
    3515 get_style = function(element, name, not_computed) {
    3516 	if (typeof element === 'string')
    3517 		element = document.getElementById(element);
    3518
    3519 	//	opacity
    3520
    3521 	if (!element || !name)
    3522 		return;
    3523
    3524 	var value, style_interface, e;
    3525 	name = name.toLowerCase();
    3526 	//	IE: element.style.styleFloat, firefox, chorme, safari: element.style.cssFloat
    3527 	//if (name === 'float') name = 'cssFloat' in element.style ? 'cssFloat' : 'styleFloat';
    3528
    3529 	if (style_interface = document.defaultView)	//	window.getComputedStyle
    3530 		try {
    3531 			if ((value = element.ownerDocument) && (value = value.defaultView))
    3532 				style_interface = value;
    3533 			else
    3534 				library_namespace.debug('Can not get .ownerDocument.defaultView of '
    3535 						+ library_namespace.node_description(element) + ' !');
    3536
    3537 			//if (/[A-Z]/.test(name)) name = name.replace(/([A-Z])/g, '-$1').toLowerCase();
    3538 			//	width 之類可能 === "auto"!!
    3539 			value = style_interface.getComputedStyle(element, null)
    3540 					// [name]
    3541 					.getPropertyValue(name);
    3542
    3543 			//	from curCSS @ jQuery: return a number for opacity
    3544 			if(name === 'opacity' && value === '')
    3545 				value = 1;
    3546 		} catch (e) {
    3547 			library_namespace.err(e);
    3548 		}
    3549
    3550 	//	IE 5-8
    3551 	else if (style_interface = element.currentStyle)
    3552 		//	IE: \w+\W\w+ (e.g., margin-bottom), firefox, chorme, safari: \w+-\w+
    3553 		//	IE8 中 width 之類可能 === "auto"!!
    3554 		value = style_interface[name === 'float' ? 'styleFloat' : name.replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); })];
    3555 		//	Dean Edwards（Base2類庫的作者）的hack	http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
    3556
    3557 	else if((style_interface = element.style) && (name in style_interface))
    3558 		value = style_interface[name];
    3559
    3560 	//	we should directly get it from element itself
    3561 	//else if (!(value = element['offset' + name.charAt(0).toUpperCase() + name.slice(1).toLowerCase()])) value = '';
    3562
    3563 	//	處理 px, pt, em, ..
    3564
    3565 	//library_namespace.debug(library_namespace.node_description(element) + '.style[' + name + '] = [' + value + ']' +(style_interface === document.defaultView ? ' (use W3C .getComputedStyle)' : style_interface === element.currentStyle ? ' (use IE .currentStyle)' : ''));
    3566
    3567 	return value;
    3568 };
    3569
    3570
    3571
    3572 CeL.interact.DOM
    3573 .
    3574 /**
    3575  * get the actual position [left,top,width,height] of an HTML node object
    3576  * @param node	HTML node object
    3577  * @return
    3578  * @memberOf	CeL.interact.DOM
    3579  * @deprecated	use get_style(), jQuery.offset(), jQuery.position()
    3580  * @see
    3581  * http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug, http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K983.aspx,
    3582  * http://msdn.microsoft.com/library/en-us/dndude/html/dude04032000.asp,
    3583  * http://www.mail-archive.com/mochikit@googlegroups.com/msg00584.html,
    3584  * http://hartshorne.ca/2006/01/20/javascript_positioning/,
    3585  * http://www.jb51.net/article/18340.htm,
    3586  * http://blog.csdn.net/wangjj_016/archive/2010/04/09/5467507.aspx
    3587  */
    3588 get_node_offset = function(node) {
    3589 	if (typeof node === 'string')
    3590 		//	若 node 為 id
    3591 		node = _.get_element(node);
    3592 	if(!_.is_element_node(node))
    3593 		return {};
    3594
    3595 	var _s = _.get_node_offset,
    3596 	offset = 'offsetWidth' in node ? {
    3597 		width : node.offsetWidth,
    3598 		height : node.offsetHeight
    3599 	} : {};
    3600
    3601
    3602 	if(node.getBoundingClientRect){
    3603
    3604 		//	also see: getClientRects()
    3605
    3606 		var s = _.get_window_status.scroll(node),
    3607 		box = node.getBoundingClientRect();
    3608
    3609 		offset = {
    3610 				left : box.left + s[0] - s[2],
    3611 				top : box.top + s[1] - s[3],
    3612 				width : box.right - box.left,
    3613 				height : box.bottom - box.top
    3614 		};
    3615
    3616 	} else if (_.is_HTML_element(node)) {
    3617 		//alert(node.id+':'+node.offsetLeft+','+node.offsetTop+';'+node.offsetWidth+','+node.offsetHeight);
    3618 		var l = 0, t = 0, p;
    3619 			// n,countH=window.navigator.userAgent.indexOf("MSIE")>=0,add=1,outsideBLOCK=1,
    3620 		if(0)
    3621 		if (typeof node.offsetWidth !== 'undefined') {
    3622 			var _w = node.offsetWidth, _h = node.offsetHeight
    3623 				// ,_o=window.getComputedStyle?document.defaultView.getComputedStyle(node,null):null
    3624 				;
    3625 			//	http://www.quirksmode.org/dom/getstyles.html
    3626 			/*
    3627 			   if(_o)	//	moz未包含margin+border+padding	這些值可能會有'em'等等的出現，不一定都是px！
    3628 				//alert(_o.getPropertyValue('border-left-width')+','+_o.getPropertyValue('border-right-width')),
    3629 				_w+=parseInt(_o.getPropertyValue('border-left-width'))+parseInt(_o.getPropertyValue('border-right-width')),
    3630 				_h+=parseInt(_o.getPropertyValue('border-top-width'))+parseInt(_o.getPropertyValue('border-bottom-width'));
    3631 			   else if(_o=node.currentStyle)	//	IE
    3632 				//	IE的offset已經包含margin+border+padding的部份??另，這些值可能會有'em'等等的出現，不一定都是px。
    3633 				_w+=parseInt(_o['borderLeftWidth'])+parseInt(_o['borderRightWidth']),
    3634 				_h+=parseInt(_o['borderTopWidth'])+parseInt(_o['borderBottomWidt都是px;
    3635 			*/
    3636 			r.width = _w,
    3637 			r.height = _h;
    3638 		}
    3639
    3640 		//	下面這段依瀏覽器而有不同 (-_-)!!
    3641 		//	position:absolute
    3642 		//var tt='';	//	for debug
    3643 		//	2006/2/14: 經由 offset 一個個溯源
    3644 		var _o = node;
    3645 		while(_o&&!isNaN(_o.offsetLeft)){	//	IE在用style:class時會出現誤差。
    3646 			/*
    3647 			   n=_o.tagName;
    3648 			   //if( !/^T(ABLE|BODY|R)$/.test(n=_o.tagName) && (countH||!/^H\d$/.test(n)) )l+=_o.offsetLeft,t+=_o.offsetTop;
    3649 			   if(n=='DIV')add=outsideBLOCK;
    3650 			   else if(n=='TD' || countH&&/^H\d$/.test(n))add=1;
    3651 			   outsideBLOCK= n=='TABLE'||n=='DIV';	//	_o.style.display
    3652 			   tt+=(add?'':'#')+n+(_o.style.display?'('+_o.style.display+')':'')+':'+_o.offsetLeft+','+_o.offsetTop+(outsideBLOCK?', outside BLOCK':'')+'\n';
    3653 			   if(add)add=0,l+=_o.offsetLeft,t+=_o.offsetTop;
    3654 			*/
    3655
    3656 			l += _o.offsetLeft || 0, t += _o.offsetTop || 0;
    3657 			_o = _o.offsetParent;//.parentNode
    3658 		}
    3659
    3660 		//		有些會用到overflow，影響位置。	2008/5/31 0:10:7
    3661 		_o = node;
    3662 		while ((_o = _o.parentNode) && _o.tagName.toLowerCase() != 'body')
    3663 			l -= _o.scrollLeft || 0, t -= _o.scrollTop || 0;
    3664
    3665 		//		need to enable definition of tt above
    3666 		//alert('l '+l+',t '+t+',w '+r.w+',h '+r.h+(typeof tt=='string'?'\n'+tt:''));
    3667
    3668 		offset.left = l;
    3669 		offset.top = t;
    3670 	}
    3671
    3672 	return offset;
    3673 };
    3674
    3675
    3676 /*
    3677 //	get the [left,top,width,height] of obj
    3678 function get_node_offset2(obj){
    3679  if(typeof obj=='string'){var o=document.getElementById(obj);if(o)obj=o;}	//	若loc為id
    3680  if(typeof obj=='object'&&typeof obj.offsetLeft!='undefined'){	//	若obj為Document Object
    3681   //alert(obj.id+':'+obj.offsetLeft+','+obj.offsetTop+';'+obj.offsetWidth+','+obj.offsetHeight);
    3682   var l=obj.offsetLeft,t=obj.offsetTop,n,add,outsideBLOCK,countH=window.navigator.userAgent.indexOf("MSIE")>=0,r=[];
    3683   if(typeof obj.offsetWidth!='undefined')r[2]=r.width=r.w=r.W=obj.offsetWidth,r[3]=r.height=r.h=r.H=obj.offsetHeight;
    3684
    3685   //	下面這段依瀏覽器而有不同 (-_-)!!
    3686   //	position:absolute
    3687   //var tt=obj.tagName+':'+obj.offsetLeft+','+obj.offsetTop+'\n';	//	for debug
    3688   while(isNaN((obj=obj.parentNode).offsetLeft)){	//	IE在用style:class時會出現誤差。
    3689    n=obj.tagName;
    3690    //if( !/^T(ABLE|BODY|R)$/.test(n=obj.tagName) && (countH||!/^H\d$/.test(n)) )l+=obj.offsetLeft,t+=obj.offsetTop;
    3691    if(n=='DIV')add=outsideBLOCK;
    3692    else if(n=='TD' || countH&&/^H\d$/.test(n))add=1;
    3693    outsideBLOCK= n=='TABLE'||n=='DIV';	//	obj.style.display
    3694    //tt+=(add?'':'#')+n+(obj.style.display?'('+obj.style.display+')':'')+':'+obj.offsetLeft+','+obj.offsetTop+(outsideBLOCK?', outside BLOCK':'')+'\n';
    3695    if(add)add=0,l+=obj.offsetLeft,t+=obj.offsetTop;
    3696   }
    3697   //alert('l'+l+',t'+t+',w'+w+',h'+h+'\n'+tt);	//	need to enable definition of tt above
    3698   r[0]=r.left=r.l=r.L=l,r[1]=r.top=r.t=r.T=t;
    3699   return r;
    3700  }
    3701 }
    3702 */
    3703
    3704 /*	locate a object(obj/div, dialogue box, popup dialog) on where we want followed window location	2005/1/12 19:-13 21:22
    3705 	此函數會盡量不使obj超出window範圍的大小，除非設定了noResize/noMove或發生錯誤。若moveable+resizable(default)，會嘗試先move再resize。
    3706 obj:
    3707 	object or id
    3708 loc:
    3709 	[left,top]/[left,top,width,height]/reference obj or id/0||'mouse':by mouse loc
    3710 		若left,top設定成%或是0.-，會當作相對於螢幕的比例。
    3711 margin:
    3712 	0/num=[num,num]/[offset x,offset y]
    3713 		在可能的情況下（不會造成超出window範圍）與loc之間空出的距離（所作的位移）。假如未輸入則自動設定。
    3714 flag:	locate_elementF.~	!表示未實作
    3715 	下面幾項為預設模式
    3716 	auto[Locate]	自動調整位置(default)，若設定abs/rel則不會自動調整。
    3717 	resizable	可調整obj大小(default) <-> noResize
    3718 	moveable	可移動obj(default) <-> noMove
    3719 	下面幾項為模式選擇，擇一。
    3720 	auto[Locate]	自動判定並調整位置(default)，若設定abs/rel則不會自動調整。
    3721 	abs[olute]	這裡的loc為絕對location。假如有提供margin，則會嘗試定位於loc+margin處。
    3722 	rel[ative]	這裡的loc為相對於window左上角的location。假如有提供margin，則會嘗試定位於loc+margin處。
    3723 	asDialog,dialog	預設是普通obj，但當設定為此項(dialog)時，loc會被當成reference obj。
    3724 			作為某obj(loc)之附屬obj（對話框/說明等），會避開主obj(reference obj)之顯示範圍。
    3725 			假如提供的loc並非obj，則會假設主obj是個從loc開始，長寬為margin的object。
    3726 	dialogDown,dialogUp,dialogRight,dialogLeft	預設是擺在下面，此flag可改成上面或其他不同方位。
    3727 	擇一
    3728 	resizable	可調整obj大小(default) <-> noResize
    3729 	noResize	不可調整obj大小，若可移動會將整個obj移到能看清的邊界。
    3730 	擇一
    3731 	moveable	可移動obj(default) <-> noMove
    3732 	noMove		不可移動obj，若可調整大小會將整個obj縮到能看清的大小。
    3733 	下面幾項可任喜好選購（笑）
    3734 	keepDisplay	是否維持顯示之display mode。沒有時則顯示之。
    3735 	create		假如不存在此obj就造出來。預設若無法取得此obj則會直接return
    3736
    3737 	!		!假如沒足夠空間則不顯示，或是僅顯示警告。
    3738
    3739 *	假如在事件中設定'eventObj=event'可掌握mouse event
    3740
    3741 TODO:
    3742 locate_elementClip=[l,t,w,h]:	resizable時將obj限制在這個範圍內
    3743
    3744 to top:
    3745 var locate_elementF;
    3746 setObjValue('locate_elementF','resizable=0,moveable=0,autoLocate=0,auto=0,absolute=1,abs=1,relative=2,rel=2,asDialog=3,dialog=3,modeFlag=3,dialogDown=3,dialogUp=7,dialogRight=11,dialogLeft=15,dialogFlag=15,dialogForce=16,noResize=32,noMove=64,keepDisplay=128,create=256',1);	//	revise
    3747 */
    3748 //locate_element[generateCode.dLK]='eventObj,locate_elementF,get_window_status,locate_element';
    3749 function locate_element(obj, loc, margin, flag) {
    3750 	// 前置處理
    3751
    3752 	// setup obj
    3753 	if (!flag)
    3754 		flag = locate_elementF.auto;
    3755 	if (!obj)
    3756 		return;
    3757 	if (typeof obj == 'string') {
    3758 		var id = obj;
    3759 		if (!(obj = document.getElementById(id)) && (flag & locate_elementF.create))
    3760 			document.body.appendChild(obj = document.createElement('div')),
    3761 					obj.id = id;
    3762 	}
    3763
    3764 	// 在 dialog 時之預設位移
    3765 	var dMargin = {
    3766 		'X' : 2,
    3767 		'Y' : 2
    3768 	}
    3769 	, Display = flag & locate_elementF.keepDisplay ? obj.style.display : 'block', Visibility = flag
    3770 			& locate_elementF.keepDisplay ? obj.style.visibility : 'visible', win, dialog = (flag & locate_elementF.modeFlag) == locate_elementF.dialog ? flag
    3771 			& locate_elementF.dialogFlag
    3772 			: 0, turnPercent = function(p, v) {
    3773 		if (typeof p == 'string') {
    3774 			var t = parseFloat(p.match(/([\d.]+)/));
    3775 			p = t ? t < 2 ? t * v : t < 200 ? t * v / 100 : t : 0;
    3776 		} else if (
    3777 				// typeof p1='undefined'&&
    3778 				isNaN(p))
    3779 			p = 0;
    3780 		return p;
    3781 	}, dealPercent = function(o, t) {
    3782 		// t: 0:loc, 1:margin
    3783
    3784 		// 是否重新指定
    3785 		var d = 0;
    3786 		if (typeof o == 'string')
    3787 			o = o.split(','), d = 1;
    3788 		if (!dialog && typeof o == 'object') {
    3789 			// 取百分比%
    3790 			if (typeof o[t ? 'L' : 'X'] == 'undefined'
    3791 					&& typeof o[0] != 'undefined')
    3792 				d = 1, o = t ? {
    3793 					'X' : o[0],
    3794 					'Y' : o[1]
    3795 				} : {
    3796 					'L' : o[0],
    3797 					'T' : o[1],
    3798 					// 假如o[2]未定義，W也會未定義（但有index）
    3799 					'W' : o[2],
    3800 					'H' : o[3]
    3801 				};
    3802 			if (t)
    3803 				o.X = turnPercent(o.X, win.windowW), o.Y = turnPercent(o.Y,
    3804 						win.windowH);
    3805 			else {
    3806 				o.L = turnPercent(o.L, win.windowW), o.T = turnPercent(o.T,
    3807 						win.windowH);
    3808 				if (typeof o.W == 'undefined') {
    3809 					delete o.W;
    3810 					delete o.H;
    3811 				} else
    3812 					o.W = turnPercent(o.W, win.windowW), o.H = turnPercent(o.H,
    3813 							win.windowH);
    3814 			}
    3815 		}
    3816 		if (d)
    3817 			if (t)
    3818 				margin = o;
    3819 			else
    3820 				loc = o;
    3821 	}, makeFit = function(l, t, r, b, hc) {
    3822 		//	test if out of range & 將box調整在range[left,top,right,bottom]內：先move，再resize
    3823 		if (boxL < l)
    3824 			boxL = l;
    3825 		if (boxT < t)
    3826 			boxT = t;
    3827 		var d = r - obj.offsetWidth;
    3828 		if (boxL > d)
    3829 			if (l > d)
    3830 				boxW = r - (boxL = l);
    3831 			else
    3832 				boxL = d;
    3833 		d = b - obj.offsetHeight;
    3834 		if (boxT > d)
    3835 			if (t > d)
    3836 				boxH = b - (boxT = t);
    3837 			else
    3838 				boxT = d;
    3839 		else if (hc && (boxT = hc - obj.offsetHeight / 2) < t)
    3840 			boxT = t;
    3841 	};
    3842
    3843 	with (obj.style) {
    3844 		overflow = visibility = 'hidden';
    3845 		if (width)
    3846 			width = '';
    3847 		if (height)
    3848 			//	重設obj。
    3849 			height = '';
    3850 		//	得設定obj之display，因為不這樣不能定offset。但可不顯現出來…只是好像沒啥效果。
    3851 		display = 'block';
    3852 	}
    3853
    3854 	// if(dialog!=locate_elementF.dialogDown&&dialog!=locate_elementF.dialogUp)dialog=0;
    3855 	// setup loc#1: deal dialog
    3856 	if (typeof loc == 'string') {
    3857 		// 若loc為id
    3858 		var o = document.getElementById(loc);
    3859 		if (o)
    3860 			loc = o;
    3861 	}
    3862 	if (typeof loc == 'object' && typeof loc.offsetLeft != 'undefined') {
    3863 		//	若loc為Document Object
    3864
    3865 		/*
    3866 		  //alert(loc.id+':'+loc.offsetLeft+','+loc.offsetTop+';'+loc.offsetWidth+','+loc.offsetHeight);
    3867 		  var l=loc.offsetLeft,t=loc.offsetTop,w,h,n,add,outsideBLOCK,countH=window.navigator.userAgent.indexOf("MSIE")>=0;	//	真妙..moz表示在<H\d>中的obj時不把H\d當作parent算進去
    3868 		  if(typeof loc.offsetWidth!='undefined')w=loc.offsetWidth,h=loc.offsetHeight;	//	loc.offsetWidth可能未定義？
    3869 		  //var tt=loc.tagName+':'+loc.offsetLeft+','+loc.offsetTop+'\n';	//	for debug
    3870 		  //	下面這段依瀏覽器而有不同 (-_-)!!
    3871 		  while(isNaN((loc=loc.parentNode).offsetLeft)){	//	IE在用style:class時會出現誤差。
    3872 		   n=loc.tagName;
    3873 		   //if( !/^T(ABLE|BODY|R)$/.test(n=loc.tagName) && (countH||!/^H\d$/.test(n)) )l+=loc.offsetLeft,t+=loc.offsetTop;
    3874 		   if(n=='DIV')add=outsideBLOCK;
    3875 		   else if(n=='TD' || countH&&/^H\d$/.test(n))add=1;
    3876 		   outsideBLOCK= n=='TABLE'||n=='DIV';	//	loc.style.display
    3877 		   //tt+=(add?'':'#')+n+(loc.style.display?'('+loc.style.display+')':'')+':'+loc.offsetLeft+','+loc.offsetTop+(outsideBLOCK?', outside BLOCK':'')+'\n';
    3878 		   if(add)add=0,l+=loc.offsetLeft,t+=loc.offsetTop;
    3879 		  }
    3880 		  //alert(l+','+t+'\n'+tt);	//	need to enable definition of tt above
    3881 		  loc={'L':l,'T':t,'W':w,'H':h};
    3882 		*/
    3883 		loc = get_node_offset(loc);
    3884 		if ((flag & locate_elementF.modeFlag) == locate_elementF.auto)
    3885 			flag += locate_elementF.dialog - locate_elementF.auto, dialog = locate_elementF.dialog;
    3886 	}
    3887
    3888 	// setup margin
    3889 	win = get_window_status();
    3890 	if (!margin)
    3891 		margin =
    3892 			// dialog?dMargin:{'X':0,'Y':0};
    3893 			dMargin;
    3894 	else
    3895 		dealPercent(margin, 1);
    3896
    3897 	// setup loc#2: deal abs/rel
    3898 	if (!loc || loc == 'mouse')
    3899 		loc = {
    3900 			L : win.mouseX || 0,
    3901 			T : win.mouseY || 0
    3902 		};
    3903 	else {
    3904 		if ((flag & locate_elementF.modeFlag) == locate_elementF.auto && typeof loc == 'string'
    3905 				&& /[%.]/.test(loc))
    3906 			flag += locate_elementF.rel - locate_elementF.auto;
    3907 		dealPercent(loc);
    3908 	}
    3909 	// alert(loc.L+','+loc.T+';'+margin.X+','+margin.Y);
    3910 	if ((flag & locate_elementF.modeFlag) == locate_elementF.auto)
    3911 		// 到這裡還沒決定就很奇怪了
    3912 		flag += locate_elementF[loc.W && loc.H && loc.T < win.windowH
    3913 				&& loc.L < win.windowW ? (dialog = locate_elementF.dialog) && 'dialog'
    3914 				: 'abs']
    3915 				- locate_elementF.auto;
    3916
    3917 	// 調整與判別
    3918 	// alert(loc.L+','+loc.T+';'+margin.X+','+margin.Y);
    3919 	// alert(loc.L+margin.X+','+(loc.T+margin.Y));
    3920 	// alert('dialog:'+dialog);
    3921
    3922 	if ((flag & locate_elementF.modeFlag) == locate_elementF.rel)
    3923 		// 改成絕對座標。此後僅存abs/dialog
    3924 		flag += locate_elementF.abs - locate_elementF.rel// -(flag&locate_elementF.modeFlag)
    3925 		, loc.L += win.scrollX, loc.T += win.scrollY;
    3926
    3927 	// 最後要設定的值
    3928 	var resizable = !(flag & locate_elementF.noResize), boxL = loc.L, boxT = loc.T, boxW = -1, boxH = -1;
    3929 	if (flag & locate_elementF.noMove)
    3930 		if (resizable)
    3931 			makeFit((boxL += margin.X) - margin.X, (boxT += margin.Y)
    3932 					- margin.Y, win.scrollX + win.windowW, win.scrollY
    3933 					+ win.windowH);
    3934 		else {
    3935 			if (margin.X < 0
    3936 					|| boxL + margin.X >= win.scrollX
    3937 					&& boxL + margin.X + obj.offsetWidth < win.scrollX
    3938 							+ win.windowW)
    3939 				boxL += margin.X;
    3940 			if (margin.Y < 0
    3941 					|| boxT + margin.Y >= win.scrollY
    3942 					&& boxT + margin.Y + obj.offsetHeight < win.scrollY
    3943 							+ win.windowH)
    3944 				boxT += margin.Y;
    3945 		}
    3946 	else if (!dialog)
    3947 		// abs
    3948 		boxL += margin.X, boxT += margin.Y, makeFit(win.scrollX, win.scrollY,
    3949 				win.scrollX + win.windowW, win.scrollY + win.windowH);
    3950 	else {
    3951 		// 自動調整位置
    3952 		if (dialog) {
    3953 			if (!loc.W)
    3954 				loc.W = 0;
    3955 			if (!loc.H)
    3956 				loc.H = 0;
    3957 		} else
    3958 			// abs時,相當於dialog在(0,0)大小(0,0)
    3959 			loc = {
    3960 				'L' : win.scrollX,
    3961 				'T' : win.scrollY,
    3962 				'W' : 0,
    3963 				'H' : 0
    3964 			};
    3965 		if (!obj.innerHTML)
    3966 			// 起碼先設定個大小以安排位置
    3967 			obj.innerHTML = ' ';
    3968
    3969 		var lA = win.scrollY + win.windowH - loc.T - loc.H, lB = loc.T
    3970 				- win.scrollY, lC = win.scrollX + win.windowW - loc.L - loc.W, lD = loc.L
    3971 				- win.scrollX,
    3972 				//	args for makeFit()
    3973 				m1 = win.scrollX, m2 = win.scrollY,
    3974 				m3 = win.scrollX + win.windowW, m4 = win.scrollY + win.windowH
    3975 				// move kind set use locate_elementF.dialog~ flag
    3976 				, movekind;
    3977 		// alert(lA+','+lB+','+lC+','+lD+'\n'+obj.offsetWidth+','+obj.offsetHeight);
    3978
    3979 	/*
    3980 		+---------------------+
    3981 		|        ^            |
    3982 		|        | lB         |	<--screen (active frame)
    3983 		|        |            |
    3984 		|<---->#####<-------->|	###:reference obj
    3985 		|  lD    |      lC    |
    3986 		|        |            |
    3987 		|        | lA         |
    3988 		|        |            |
    3989 		+---------------------+
    3990 	*/
    3991 		// 決定 mode
    3992 		if (dialog && (flag & locate_elementF.dialogForce))
    3993 			movekind = dialog;
    3994 		else {
    3995 			if (obj.offsetWidth < win.windowW
    3996 					&& (dialog != locate_elementF.dialogRight
    3997 							&& dialog != locate_elementF.dialogLeft || obj.offsetHeight >= win.windowH))
    3998 				if (obj.offsetHeight < lA
    3999 						&& (dialog != locate_elementF.dialogUp || obj.offsetHeight >= lB))
    4000 					movekind = locate_elementF.dialogDown;
    4001 				else if (obj.offsetHeight < lB)
    4002 					movekind = locate_elementF.dialogUp;
    4003 			if (!movekind && obj.offsetHeight < win.windowH)
    4004 				if (obj.offsetWidth < lC
    4005 						&& (dialog != locate_elementF.dialogLeft || obj.offsetWidth >= lD))
    4006 					movekind = locate_elementF.dialogRight;
    4007 				else if (obj.offsetWidth < lD)
    4008 					movekind = locate_elementF.dialogLeft;
    4009 			if (!movekind)
    4010 				movekind =
    4011 					// 以較大、可視的為準
    4012 					dialog != locate_elementF.dialogRight && dialog != locate_elementF.dialogLeft ?
    4013 						// 沒考慮假如lA<5時..
    4014 						lA < lB && resizable ? locate_elementF.dialogUp : locate_elementF.dialogDown :
    4015 						//
    4016 						lC < lD && resizable ? locate_elementF.dialogLeft : locate_elementF.dialogRight;
    4017 		}
    4018
    4019 		// alert(movekind);
    4020 		// 決定location
    4021 		if (movekind == locate_elementF.dialogDown)
    4022 			m2 = loc.T + loc.H, boxT += loc.H;
    4023 		else if (movekind == locate_elementF.dialogUp)
    4024 			m4 = loc.T, boxT -= obj.offsetHeight, margin.Y = -margin.Y;
    4025 		else if (movekind == locate_elementF.dialogRight)
    4026 			m1 = loc.L + loc.W, boxL += loc.W;
    4027 		else
    4028 			m3 = loc.L, boxL -= obj.offsetWidth, margin.X = -margin.X;
    4029 		//else if(movekind==locate_elementF.dialogLeft)
    4030
    4031 		// 加上偏移
    4032 		boxL += margin.X, boxT += margin.Y;
    4033 		if (!resizable) {
    4034 			if (boxL < m1 && margin.X < 0 || boxL + obj.offsetWidth > m3
    4035 					&& margin.X > 0)
    4036 				boxL -= margin.X;
    4037 			if (boxT < m2 && margin.Y < 0 || boxT + obj.offsetHeight > m4
    4038 					&& margin.Y > 0)
    4039 				boxT -= margin.Y;
    4040 			//	確保不會撞到
    4041 			m3 += obj.offsetWidth, m4 += obj.offsetHeight;
    4042 		}
    4043 		// 奇怪的是，alert(obj.offsetWidth)後obj.offsetWidth就變成0了。可能因為這值需要出函數之後再改。
    4044 		// alert(resizable+'\n'+m1+','+m2+','+m3+','+m4+','+movekind+'\n'+obj.offsetWidth+','+obj.offsetHeight);
    4045 		makeFit(m1, m2, m3, m4, movekind == locate_elementF.dialogRight
    4046 				|| movekind == locate_elementF.dialogLeft ? loc.T : 0);
    4047 	}
    4048
    4049 	// 設定位置
    4050 	// alert(boxL+','+boxT+','+boxW+','+boxH+','+Display);
    4051 	with (obj.style) {
    4052 		position = 'absolute';
    4053 		left = boxL + 'px';
    4054 		top = boxT + 'px';
    4055 		if (boxW >= 0 || boxH >= 0) {
    4056 			overflow = 'auto';
    4057 			//alert(width+','+height+'\n'+typeof width+'\n->w,h:'+boxW+','+boxH);
    4058 			if (boxW >= 0)
    4059 				width = boxW + 'px';
    4060 			if (boxH >= 0)
    4061 				height = boxH + 'px';
    4062 		}
    4063 		display = Display;
    4064 		visibility = Visibility;
    4065 	}
    4066
    4067 	// alert(obj.style.width+','+obj.style.height+'\n'+obj.offsetWidth+','+obj.offsetHeight);
    4068 	return obj;
    4069 };
    4070
    4071
    4072
    4073
    4074
    4075
    4076
    4077
    4078
    4079 //	2007/4/25-27 0:48:22	RFC 3492 IDNA Punycode	未最佳化
    4080 //	http://stackoverflow.com/questions/183485/can-anyone-recommend-a-good-free-javascript-for-punycode-to-unicode-conversion
    4081 //	http://xn-punycode.com/
    4082 function Punycode(){}
    4083
    4084 Punycode.map='abcdefghijklmnopqrstuvwxyz0123456789',
    4085 Punycode.Dmap=0,
    4086 Punycode.base=36,//Punycode.map.length
    4087 Punycode.tmin=1,
    4088 Punycode.tmax=26,
    4089 Punycode.skew=38,
    4090 Punycode.damp=700,
    4091 Punycode.initial_bias=72,//偏移
    4092 Punycode.initial_n=0x80,//128
    4093 Punycode.prefix="xn--",//the default ACE prefix
    4094 Punycode.delimiter='-';
    4095 Punycode._b=Punycode.base-Punycode.tmin,
    4096 //Punycode._t=(Punycode._b*Punycode.tmax)>>1,
    4097 Punycode._t=Math.floor(Punycode._b*Punycode.tmax/2);
    4098
    4099 //	IDNA ToASCII
    4100 Punycode.encodeDomain=function(UURL){
    4101  var m=UURL.match(/^([\w\d\-]+:\/\/)?([^\/]+)/),UDomain=m?m[2]:'',i=(m=UDomain)?UURL.indexOf(m):0;
    4102 	//document.write('<hr/>Punycode.encodeDomain UDomain: ['+i+']['+m+']<br/>');
    4103  if(m&&m.replace(/[\x01-\x7f]+/g,''))with(Punycode)
    4104   m=m.replace(/([^.]+)\./g,function($0,$1){
    4105 	//document.write($1+'→'+encode($1)+'<br/>');
    4106 	 return prefix+encode($1)+'.';
    4107 	}),UURL=encodeURI(UURL.slice(0,i)+m+UURL.slice(i+UDomain.length));
    4108  return UURL;
    4109 };
    4110
    4111 //	IDNA ToUnicode
    4112 Punycode.decodeDomain=function(PURL){with(Punycode){
    4113  var m=PURL.match(/^([\w\d\-]+:\/\/)?([^\/]+)/),PDomain=m?m[2]:'',i=(m=PDomain)?PURL.indexOf(m):0;
    4114 	//document.write('<hr/>Punycode.decodeDomain PDomain: ['+i+']['+m+']<br/>');
    4115  if(m){
    4116   m=m.replace(new RegExp(prefix+'([^.]+)\\.','g'),function($0,$1){
    4117 	//document.write($1+'→'+decode($1)+'<br/>');
    4118 	 return decode($1)+'.';
    4119 	});
    4120   if(m!=PDomain){
    4121    PURL=PURL.slice(0,i)+m+PURL.slice(i+PDomain.length);
    4122    try{PURL=decodeURI(PURL);}catch(e){PURL=unescape(PURL);}
    4123   }
    4124  }
    4125  return PURL;
    4126 }};
    4127
    4128
    4129 Punycode.adapt=function(delta,numpoints,firsttime){with(Punycode){
    4130 	//document.write('*adapt: '+delta+', '+numpoints+', '+firsttime+', _b='+_b+', _t='+_t+'<br/>');
    4131  delta=firsttime?Math.floor(delta/damp):delta>>1;//Math.floor(delta/(firsttime?damp:2));
    4132  delta+=Math.floor(delta/numpoints);
    4133  var k=0;
    4134  for(;delta>_t;k+=base)delta=Math.floor(delta/_b);
    4135  return k+Math.floor((_b+1)*delta/(delta+skew));
    4136 }};
    4137
    4138 Punycode.encode=function(UString){with(Punycode){
    4139  var n=initial_n,cA=[],m,mA=[],i=0,c
    4140 	,q,delta=0,bias=initial_bias,output=UString.replace(/[^\x01-\x7f]+/g,''),h=output.length,b=h;
    4141 	//document.write('<hr/>Punycode.encode begin: ['+output+']<br/>');
    4142  if(b)output+=delimiter;
    4143
    4144  for(;i<UString.length;i++){
    4145   cA.push(c=UString.charCodeAt(i));
    4146   if(c>n)mA.push(c);
    4147  }
    4148  mA.sort(function(a,b){return b-a;});
    4149
    4150  while(h<cA.length){
    4151   do{c=mA.pop();}while(m==c);	//	預防重複
    4152   m=c;
    4153   //if(m-n>(Number.MAX_VALUE-delta)/(h+1)){alert('Punycode: overflow');return;}
    4154   delta+=(m-n)*(h+1);//	should test overflow
    4155   n=m;
    4156   for(i=0;i<cA.length;i++){
    4157    if(c=cA[i],c<n)++delta;//if(c=cA[i],c<n&&!++delta){alert('Punycode: overflow');return;}//	fail on overflow
    4158 	//document.write('<b>'+UString.charAt(i)+' '+(c.toString(16)+','+n.toString(16)).toUpperCase()+'</b><br/>');
    4159    if(c==n){
    4160     for(q=delta,k=base;;k+=base){
    4161      t=k<=bias/* +tmin not needed */?tmin:k>=bias+tmax?tmax:k-bias;
    4162      if(q<t)break;
    4163      output+=map.charAt(t+(q-t)%(base-t));
    4164 	//document.write('<b>'+output+'</b><br/>');
    4165      q=Math.floor((q-t)/(base-t));
    4166     }
    4167     output+=map.charAt(q);
    4168     bias=adapt(delta,h+1,h==b);
    4169 	//document.write('h='+h+'/'+cA.length+', bias='+bias+', '+output+'<br/>');
    4170     delta=0,h++;
    4171    }
    4172   }
    4173   delta++,n++;
    4174  }
    4175 	//document.write(UString+'→'+output+'<br/>');
    4176  return output;
    4177 }};
    4178
    4179 Punycode.decode=function(PCode){with(Punycode){
    4180  var n=initial_n,i=0,p=PCode.lastIndexOf(delimiter),bias=initial_bias,output=p==-1?'':PCode.slice(0,p)
    4181 	,oldi,w,digit,l;
    4182 	//document.write('<hr/>Punycode.decode begin: ['+output+']<br/>');
    4183  if(!Dmap)for(w=0,Dmap={};w<map.length;w++)Dmap[map.charAt(w)]=w;//,document.write('Dmap['+map.charAt(w)+']='+w+'<br/>');
    4184  while(p<PCode.length-1){
    4185   for(oldi=i,w=1,k=base;;k+=base){
    4186    if(++p>=PCode.length){alert('Punycode: invalid input: out of range');return PCode;}
    4187 	//document.write('PCode.charAt('+p+')'+' = '+PCode.charAt(p)+' → '+Dmap[PCode.charAt(p)]+'<br/>');
    4188    if(isNaN(digit=Dmap[PCode.charAt(p)])){alert('Punycode: invalid input');return PCode;}
    4189    //if(digit>(Number.MAX_VALUE-i)/w){alert('Punycode: overflow');return;}
    4190    i+=digit*w;
    4191    t=k<=bias/* +tmin not needed */?tmin:k>=bias+tmax?tmax:k-bias;
    4192 	//document.write('i='+i+', t='+t+', digit='+digit+', k='+k+'<br/>');
    4193    if(digit<t)break;
    4194    //if(w>Number.MAX_VALUE/(base-t)){alert('Punycode: overflow');return;}
    4195    w*=base-t;
    4196   }
    4197   bias=adapt(i-oldi,l=output.length+1,oldi==0);
    4198 	//document.write('bias='+bias+', n='+n+', i='+i+', l='+l+'<br/>');
    4199   //if(i/l>Number.MAX_VALUE-n){alert('Punycode: overflow');return;}
    4200   n+=Math.floor(i/l);
    4201   i%=l;
    4202 	//document.write('['+output.length+']'+output+'+'+n+'(0x'+n.toString(16).toUpperCase()+')@'+i+'→');
    4203   output=output.slice(0,i)+String.fromCharCode(n)+output.slice(i);
    4204 	//document.write('['+output.length+']'+output+'<br/>');
    4205   i++;
    4206  }
    4207 	//document.write(PCode+'→'+output+'<br/>');
    4208  return output;
    4209 }};
    4210
    4211
    4212 /*
    4213 var testC='Hello-Another-Way--fc4qua05auwb3674vfr0b',rC;
    4214 document.write('<hr/>'+
    4215 //Punycode.encodeDomain('http://國際.計畫.org/國際.計畫.htm')
    4216 Punycode.decodeDomain('http://xn--9cs229l.xn--gpyr35b.org/%E5%9C%8B%E9%9A%9B.%E8%A8%88%E7%95%AB.htm')
    4217 //Punycode.encode('463578')
    4218 //Punycode.decode('ihqwcrb4cv8a8dqg056pqjye')+'<hr/>'+Punycode.encode('他们为什么不说中文')
    4219 //Punycode.decode('ihqwctvzc91f659drss3x8bo0yb')+'<hr/>'+Punycode.encode('他們爲什麽不說中文')
    4220 //(rC=Punycode.decode(testC))+'<hr/>'+(rC=Punycode.encode(rC))+'<hr/>'+(testC==rC?'OK':'<b style="color:red">FAILED</b>:<br/>'+testC+'<br/>'+rC)
    4221 );
    4222 */
    4223
    4224
    4225
    4226 /*	一個非常不好的 deal onload 方法。只在onload不具有arguments時有用，應該亦可用setTimeout('~',0)
    4227 	where	0:back,1:front
    4228
    4229 for IE:
    4230 <!--[if IE]><script defer type="text/javascript">
    4231 //	onload code
    4232 </script><![endif]-->
    4233
    4234 c.f.	http://www.brothercake.com/	http://simonwillison.net/2004/May/26/addLoadEvent/
    4235 	GO1.1 Generic onload by Brothercake
    4236 	window.addEventListener,document.addEventListener,typeof window.attachEvent
    4237 c.f.	setTimeout('~',0);	不過這不能確定已經load好
    4238 */
    4239 /*
    4240 function addonload(s,where){
    4241  if(!s||typeof window!='object')return 1;
    4242  if(typeof s=='function'){
    4243   s=parseFunction(s);
    4244   if(!s||!s.funcName)return 2;
    4245   s=s.funcName+'()';
    4246  }
    4247  var o=window.onload?typeof window.onload=='string'?window.onload:parseFunction(window.onload).contents:'';
    4248  window.onload=new Function(where?s+';\n'+o:o+';\n'+s);
    4249 }
    4250 */
    4251
    4252
    4253 CeL.interact.DOM
    4254 .
    4255 DOM_loaded = function () {
    4256 	if (document.body)
    4257 		return _.DOM_loaded = function () { return true; };
    4258 	else
    4259 		return false;
    4260 };
    4261
    4262
    4263 /*
    4264 // The DOM ready check for Internet Explorer
    4265 try{document.documentElement.doScroll('left');}
    4266 catch(e){setTimeout(arguments.callee, 50);return;}
    4267
    4268 */
    4269 CeL.interact.DOM
    4270 .
    4271 /**
    4272  * 比較好點的 add onload。
    4273  * 比起 add_listener()，本函數在已經 load 時依然會執行，而 add_listener 因為是用榜定的方法，因此 load 完就不再觸發(?)。
    4274  * 這東西頂多只能擺在 include 的 JS file 中，不能 runtime include。
    4275  * @example
    4276  * CeL.use('net.web');
    4277  * CeL.on_load(function(){sl(1);},'sl(2);');
    4278  * @requires	_.add_listener,_.DOM_loaded
    4279  * @see
    4280  * jQuery: $(document).ready(listener);
    4281  * DOMContentLoaded	http://webdesign.piipo.com/jquery/jquery_events
    4282  * 可直接參考 SWFObject。
    4283  * TODO:
    4284  * <a href="http://javascript.nwbox.com/IEContentLoaded/" accessdate="2010/6/3 11:15" title="IEContentLoaded - An alternative for DOMContentLoaded on Internet Explorer">IEContentLoaded</a>
    4285  * DOMContentLoaded是firefox下特有的Event, 當所有DOM解析完以後會觸發這個事件。
    4286  * DOMContentLoaded與DOM中的onLoad事件與其相近。但onload要等到所有頁面元素加載完成才會觸發, 包括頁面上的圖片等等。
    4287  * <a href="http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/06/05/jquery-ready-vs-load.aspx" accessdate="2010/6/3 11:17">jQuery ready vs load - 黑暗執行緒</a>
    4288  * $(document).ready(fn)發生在"網頁本身的HTML"載入後就觸發，而$(window).load(fn)則會等到"網頁HTML 標籤中引用的圖檔、內嵌物件(如Flash)、IFrame"等拉哩拉雜的東西都載入後才會觸發。
    4289  * @memberOf	CeL.interact.DOM
    4290  */
    4291 on_load = function on_load() {
    4292 	var _s = _.on_load, loaded=_.DOM_loaded(),i = 0, a = arguments, l = a.length;
    4293 	for (; i < l; i++)
    4294 		if(loaded)
    4295 			a[i].call(document);
    4296 		else
    4297 			_.add_listener('load', a[i], document);
    4298 };
    4299
    4300
    4301 CeL.interact.DOM
    4302 .
    4303 /**
    4304  * bind/add listener. register event control, setup code to run.
    4305  * listener 應該加上 try{}catch{}，否則會搞不清楚哪裡出問題。
    4306  * **	對同樣的 object，事件本身還是會依照 call add_listener() 的順序跑，不會因為 p_first 而改變。
    4307  * **	NOT TESTED!!
    4308  * TODO:
    4309  * removeEventListener,
    4310  * remove_listener(),
    4311  * default 'this'
    4312  * 自訂 event
    4313  *
    4314  * @param {string} type	listen to what event type. event name/action
    4315  * @param listener	listener function/function array/function string,
    4316  * 				須 String 之 recursive function 時可 "(function(){return function f(){f();};})()"
    4317  * 			function(e){var target=e?e.target:(e=window.event).srcElement;if(e.stopPropagation)e.stopPropagation();else e.cancelBubble=true;if(e.preventDefault)e.preventDefault();else e.returnValue=false;return false;}
    4318  * @param [target_element]	bind/attach to what HTML element
    4319  * @param [p_first]	parentNode first
    4320  * @return
    4321  * @since	2010/1/20 23:42:51
    4322  * @see
    4323  * c.f., GEvent.add_listener()
    4324  * @memberOf	CeL.interact.DOM
    4325  */
    4326 add_listener = function add_listener(type, listener, target_element, p_first) {
    4327 	if (!type || !listener)
    4328 		return;
    4329
    4330 	if (typeof listener === 'string')
    4331 		listener = new Function('e', listener);
    4332
    4333 	if (typeof target_element === 'string')
    4334 		target_element = _.get_element(target_element);
    4335
    4336 	var _s = _.add_listener, i, adder;
    4337
    4338 	if(typeof p_first !== 'bool')
    4339 		p_first = typeof p_first === 'undefined' ? _s.p_first : !!p_first;
    4340
    4341 	//	進階功能
    4342 	if (library_namespace.is_Object(type))
    4343 		// usage: add_listener({unload:Unload});
    4344 		// usage: add_listener({load:{true:[function(){sl(1);},'sl(2);']}});
    4345 		for (i in type)
    4346 			_s(i, type[i], target_element, p_first);// ,sl(i+': '+type[i])
    4347
    4348 	//	Array or Object
    4349 	else if (library_namespace.is_Object(listener))
    4350 		// usage: add_listener('unload',{true:Unload1});
    4351 		// usage: add_listener('unload',[Unload1,Unload2]);
    4352 		// 因為 Array 會從最小的開始照順序出，所以這邊不再判別是否為 Array。
    4353 		for (i in listener)
    4354 			// if(isNaN(f))sl('add_listener: to '+i),_s.p_first=i==='true';//||i==1||i===true
    4355 			_s(type, listener[i], target_element,
    4356 					i === 'true' || (i === 'false' ? false : undefined));// ,sl((typeof i)+' ['+i+'] '+_s.p_first)
    4357
    4358 	else if(library_namespace.is_Function(listener)){
    4359 		/*
    4360 		 * 先設定好 native listener adding function
    4361 		 */
    4362 		if (target_element)
    4363 			adder = target_element.addEventListener;
    4364 		else if (!(adder = _s.global_adder) && adder !== null)
    4365 			_s.global_adder = adder = _s.get_adder();
    4366
    4367 		//$(document).ready(listener);
    4368
    4369 		//	使 listener 能以 this 取得 target_element
    4370 		i = function(e) {
    4371 			if(!e)
    4372 				e = window.event;
    4373
    4374 			//	正規化 Document Object Model (DOM) Level 3 Events
    4375 			//	http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#interface-Event
    4376 			if(!e.currentTarget)
    4377 				e.currentTarget = target_element;
    4378 			if(!e.target)
    4379 				e.target = e.srcElement || target_element;
    4380
    4381 			//	from fix in jQuery
    4382
    4383 			// check if target is a textnode (safari)
    4384 			if ( e.target.nodeType === 3 )
    4385 				e.target = e.target.parentNode;
    4386
    4387 			// Add relatedTarget, if necessary
    4388 			if ( !e.relatedTarget && e.fromElement )
    4389 				e.relatedTarget = e.fromElement === e.target ? e.toElement : e.fromElement;
    4390
    4391 			//	取得滑鼠座標
    4392 			//	http://hartshorne.ca/2006/01/23/javascript_cursor_position/
    4393 			//	http://hartshorne.ca/2006/01/18/javascript_events/
    4394 			if ( isNaN(e.pageX) && !isNaN(e.clientX) ) {
    4395 				var s = _.get_window_status.scroll();
    4396 				e.pageX = e.clientX + s[0] - s[2];
    4397 				e.pageY = e.clientY + s[1] - s[3];
    4398 			}
    4399
    4400 			listener.call(target_element, e);
    4401 		};
    4402
    4403 		// 主要核心動作設定之處理
    4404 		//	TODO: 在 onload 時使 target_element = null
    4405 		// sl(type+' ('+((typeof p_first=='undefined'?_s.p_first:p_first?true:false)?'p_first':'run first')+'): '+listener);
    4406 		if(adder){
    4407 			try{
    4408 				//	直接用 target_element.addEventListener 不會有問題。
    4409 				//	.call(window.document): for Chrome 'Illegal invocation' issue
    4410 				//	http://stackoverflow.com/questions/1007340/javascript-function-aliasing-doesnt-seem-to-work
    4411 				//	但 IE9 需要 .call(target_element) 或者別用 .call，否則會得到 "Invalid procedure call or argument"
    4412 				adder.call(target_element, type, i, p_first);
    4413 			}catch(e){
    4414 				adder.call(window.document, type, i, p_first);
    4415 			}
    4416 			return;
    4417 		}
    4418
    4419 		return target_element && (adder = target_element.attachEvent) ?
    4420 			// http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx
    4421 			adder('on' + type, i)
    4422
    4423 		: _s.default_adder(type, i, p_first, target_element)
    4424 		;
    4425 	}
    4426
    4427 };
    4428
    4429 CeL.interact.DOM
    4430 .
    4431 /**
    4432  * useCapture: parentNode first
    4433  * @see
    4434  * <a href="http://www.w3.org/TR/DOM-Level-3-Events/#event-flow" accessdate="2010/4/16 22:40">Document Object Model (DOM) Level 3 Events Specification</a>,
    4435  * <a href="http://www.w3.org/TR/DOM-Level-3-Events/#interface-EventTarget" accessdate="2010/4/16 22:42">Interface EventTarget</a>
    4436  */
    4437 add_listener.p_first = false;
    4438
    4439 CeL.interact.DOM
    4440 .
    4441 /**
    4442  * get (native) global listener adding function.
    4443  * TODO: 只設定一次
    4444  * historical for Netscape Navigator, mozilla: window.captureEvents, document.captureEvents
    4445  */
    4446 add_listener.get_adder = function() {
    4447 	/**
    4448 	 * moz (gecko), safari 1.2, ow5b6.1, konqueror, W3C standard: window.addEventListener
    4449 	 * @ignore
    4450 	 * @see
    4451 	 * <a href="https://developer.mozilla.org/en/DOM/element.addEventListener" accessdate="2010/4/16 22:35">element.addEventListener - MDC</a>
    4452 	 * <a href="http://simonwillison.net/2004/May/26/addLoadEvent/" accessdate="2010/4/16 22:36">Executing JavaScript on page load</a>
    4453 	 */
    4454 	return window.addEventListener ||
    4455 	/*
    4456 	 * opera 7.50, ie5.0w, ie5.5w, ie6w: window.attachEvent
    4457 	 * opera 7.50: document.attachEvent
    4458 	 */
    4459 	window.attachEvent ? function(t, l) {
    4460 		window.attachEvent('on' + t, l);
    4461 	} :
    4462 	/*
    4463 	 * MSN/OSX, opera 7.50, safari 1.2, ow5b6.1: document.addEventListener
    4464 	 */
    4465 	document.addEventListener ||
    4466 	/*
    4467 	 * ie5m, MSN/OSX, ie5.0w, ie5.5w ie6w: document.onreadystatechange
    4468 	 */
    4469 	null;
    4470
    4471 };
    4472
    4473 CeL.interact.DOM
    4474 .
    4475 /**
    4476  * 含括其他情況。
    4477  * all: window.onload.
    4478  * TODO: use queue
    4479  * @param type	listen to what event type
    4480  * @param listener	listener function/function array
    4481  * @param [p_first]	parentNode first
    4482  * @param [target_element]	bind/attach to what HTML element
    4483  * @return
    4484  * @see
    4485  * http://blog.othree.net/log/2007/02/06/third-argument-of-addeventlistener/
    4486  */
    4487 add_listener.default_adder = function(type, listener, p_first, target_element) {
    4488 	if(!target_element)
    4489 		target_element = window;
    4490
    4491 	var old = target_element[type = 'on' + type];
    4492
    4493 	return target_element[type] =
    4494 		old ?
    4495 			//	TODO: typeof old==='string'
    4496 			p_first ? function(e) {
    4497 				old.call(target_element, e || window.event);
    4498 				listener.call(target_element, e || window.event);
    4499 			} : function(e) {
    4500 				listener.call(target_element, e || window.event);
    4501 				old.call(target_element, e || window.event);
    4502 			}
    4503 		:
    4504 			listener
    4505 		;
    4506 };
    4507
    4508 CeL.interact.DOM
    4509 .
    4510 /**
    4511  * TODO:
    4512  * listener list.
    4513  * 當無法執行 DOM 操作時（尚未載入、版本太舊不提供支援等）以此為主。
    4514  * add_listener.list[node][event type]=[listener list]
    4515  */
    4516 add_listener.list = {};
    4517
    4518 CeL.interact.DOM
    4519 .
    4520 /**
    4521  * TODO:
    4522  * 觸發函數.
    4523  * 當無法執行 DOM 操作時（尚未載入、版本太舊不提供支援等）以此為主。
    4524  * add_listener.list[type]=[listener list]
    4525  */
    4526 add_listener.list = {};
    4527
    4528
    4529
    4530 CeL.interact.DOM
    4531 .
    4532 /**
    4533  * 阻止 JavaScript 事件冒泡傳遞，使 event 不傳到 parentNode。
    4534  * @param e	event handle
    4535  * @param c	cancel bubble
    4536  * @see
    4537  * http://www.jb51.net/html/200705/23/9858.htm
    4538  * @memberOf	CeL.interact.DOM
    4539  */
    4540 stop_event = function(e, c) {
    4541 	if (!e)
    4542 		e = window.event;
    4543
    4544 	if(e.preventDefault)
    4545 		e.preventDefault();
    4546 	else
    4547 		e.returnValue = false;
    4548
    4549 	if(c)
    4550 		// cancelBubble 在IE下有效，stopPropagation 在 Firefox 下有效。
    4551 		// 停止冒泡，事件不會上升，我們就可以獲取精確的鼠標進入元素。 http://realazy.org/lab/bubble/
    4552 		if(e.stopPropagation)
    4553 			e.stopPropagation();
    4554 		else
    4555 			e.cancelBubble = true;
    4556 };
    4557
    4558
    4559
    4560 CeL.interact.DOM
    4561 .
    4562 /**
    4563  * 獲取頁面上選中的選取區資訊。
    4564  *
    4565  * @example
    4566  * CeL.add_listener('mouseup', function (e) { var s = CeL.get_selection(); if (s && s.text) CeL.debug('select @' + this + '(' + s.element + ')' + ' (' + s.left + '+' + s.width + ',' + s.top + '+' + s.height + '), (' + e.pageX + ',' + e.pageY + '): ' + s.text); }, target_element);
    4567  *
    4568  * @param	{Number} [index]	TODO: 第幾選取區, default: all or 0 if there's only ONE/ZERO selection
    4569  * @return	{Object}
    4570  * 	{
    4571  * 		left: {Number} in px,
    4572  * 		top: {Number} in px,
    4573  * 		width: {Number} in px,
    4574  * 		height: {Number} in px,
    4575  * 		text: {String} 文字,
    4576  * 		element: {HTMLElement},
    4577  * 		selection: selection object (browser dependent)
    4578  * 	}
    4579  * @return	{undefined}	error.
    4580  * @see
    4581  * http://plugins.jquery.com/project/selectedText,
    4582  * Gecko: https://developer.mozilla.org/en/DOM/Selection
    4583  * @memberOf	CeL.interact.DOM
    4584  */
    4585 get_selection = function(index) {
    4586 };
    4587
    4588
    4589 try{
    4590
    4591 	if (window.getSelection)
    4592 		_.get_selection = function(index) {
    4593 			//	Firefox, Opera, Safari
    4594 			//	http://help.dottoro.com/ljcvonpc.php
    4595 			//	Although the selection object is supported by Opera, it is only partially suppported. The window.getSelection method provides more complex functionality in that browser.
    4596 			//	http://www.dotvoid.com/2001/03/using-the-range-object-in-mozilla/
    4597 			var e = document.activeElement,
    4598 			//	在 Opera 中，e 為 [object Text]
    4599 			tag = e && e.tagName && e.tagName.toLowerCase(),
    4600 			s = window.getSelection();
    4601 			if(!s.rangeCount)
    4602 				//	點擊而無選擇?
    4603 				//	最起碼回應能得知的資訊
    4604 				return {
    4605 					text : '',
    4606 					element: s,
    4607 					selection: s
    4608 				};
    4609
    4610 			//	超出範圍可能會 Error: INDEX_SIZE_ERR: DOM Exception 1
    4611 			s = s.getRangeAt(!isNaN(index) && 0 <= index
    4612 					&& index < s.rangeCount ? index : 0);
    4613
    4614 			//	Gecko: https://developer.mozilla.org/en/DOM/range
    4615 			//	除了 Gecko 外，都有 s.getBoundingClientRect 但無 s.endContainer.getBoundingClientRect。
    4616 			//	Gecko 可以取 mouse event 作 workaround
    4617 			//library_namespace.debug(s.endContainer.parentNode);
    4618 			var offset = _.get_node_offset(
    4619 					s.getBoundingClientRect ? s : s.endContainer.parentNode
    4620 				);
    4621
    4622 			return {
    4623 				//	TODO: offset
    4624 				//	TODO: do test
    4625 				//s.startOffset,
    4626 				left : offset.left,
    4627 				top : offset.top,
    4628 				//s.endOffset,
    4629 				width : offset.width,
    4630 				height : offset.height,
    4631 				text : tag === 'textarea' || tag === 'input' || tag === 'select'
    4632 						? e.value.substring(e.selectionStart, e.selectionEnd)
    4633 						: s.toString(),
    4634 				element: s,//s.endContainer,
    4635 				selection: s
    4636 			};
    4637
    4638 		};
    4639
    4640 	else if (document.selection && document.selection.createRange) {
    4641 		// Internet Explorer
    4642 		// http://msdn.microsoft.com/en-us/library/ms534692%28VS.85%29.aspx
    4643 		// TODO: http://help.dottoro.com/ljefwsqm.php
    4644
    4645 		document.execCommand
    4646 		&& document.execCommand('MultipleSelection', true, true);
    4647
    4648 		_.get_selection = function(input) {
    4649 			var s = document.selection.createRange();
    4650
    4651 			return s.type !== 'None' && {
    4652 				//	TODO: do test
    4653 				//	http://msdn.microsoft.com/en-us/library/ms535872%28v=VS.85%29.aspx
    4654 				//	s.offsetLeft, s.offsetTop 較不準
    4655 				left : s.boundingLeft,
    4656 				top : s.boundingTop,
    4657 				width : s.boundingWidth,
    4658 				height : s.boundingHeight,
    4659 				text : s.text,
    4660 				//	TODO
    4661 				//element: null,
    4662 				selection: s
    4663 			};
    4664
    4665 		};
    4666
    4667 	} else if (document.getSelection)
    4668 		_.get_selection = function(input) {
    4669 			return {
    4670 				//	TODO: get offset from mouse location
    4671 				text : document.getSelection()
    4672 			};
    4673 		};
    4674
    4675 }catch (e) {
    4676 	// TODO: handle exception
    4677 }
    4678
    4679 /*
    4680 	↑HTML only	-------------------------------------------------------
    4681 */
    4682
    4683
    4684
    4685 var is_IE=/*@cc_on!@*/!true;
    4686
    4687 /*
    4688 http://www.real-blog.com/programming/259
    4689 http://fettig.net/weblog/2006/10/09/detecting-ie7-in-javascript/
    4690
    4691 if(typeof window.XMLHttpRequest!="undefined"){
    4692  // IE 7, mozilla, safari, opera 9
    4693 }else{
    4694  // IE6, older browsers
    4695 }
    4696 */
    4697
    4698
    4699
    4700
    4701
    4702 /*
    4703 http://www.cnlei.org/blog/article.asp?id=337
    4704 在IE下：
    4705 >> 支持keyCode
    4706 >> 不支持which和charCode,二者值為 undefined
    4707
    4708 在Firefox下：
    4709 >> 支持keyCode，除功能鍵外，其他鍵值始終為 0
    4710 >> 支持which和charCode，二者的值相同
    4711
    4712 在Opera下：
    4713 >> 支持keyCode和which，二者的值相同
    4714 >> 不支持charCode，值為 undefined
    4715
    4716 */
    4717 CeL.interact.DOM
    4718 .
    4719 /**
    4720  * 條碼器(Barcode Scanner)/雷射讀碼器的輸入可用 onkeypress 取得
    4721  * @param callback	callback
    4722  * @return
    4723  * @since	2008/8/26 23:10
    4724  * @example
    4725  * //	usage:
    4726  * deal_barcode(function(t) {
    4727  * 	if (t.length > 9 && t.length < 17)
    4728  * 		document.getElementById("p").value = t,
    4729  * 		document.forms[0].submit();
    4730  * });
    4731  * @memberOf	CeL.interact.DOM
    4732  */
    4733 deal_barcode = function (callback) {
    4734 	var k, lt = 0, st = 0;
    4735 	document.onkeypress = function(e) {
    4736 		var c = new Date();
    4737 		if (
    4738 				// 前後不超過 800，
    4739 				c - st > 800 ||
    4740 				// 與上一輸入不超過 90
    4741 				c - lt > 90) {
    4742 			st = c;
    4743 			k = "";
    4744 		}
    4745 		lt = c;
    4746 		c = e || window.event;
    4747 		c = c.keyCode || c.which || c.charCode;
    4748 		if (c > 32 && c < 120)
    4749 			k += String.fromCharCode(c);
    4750 		else if (c == 13)
    4751 			callback(k, e);
    4752 	};
    4753
    4754 };
    4755
    4756
    4757
    4758 //	https://addons.mozilla.org/js/search-plugin.js
    4759 //	TODO, & Chrome
    4760 function addEngine(){
    4761 }
    4762
    4763
    4764
    4765 //	for string encoding	-------------------------------------------------------
    4766 //	將HTML:&#ddd; → Unicode text
    4767 //	此函數只能用一次，為輸入資料良好之情況下使用。完整版： HTML_to_Unicode
    4768 //turnUnicode[generateCode.dLK]='setTool,getText';
    4769 function turnUnicode(b){
    4770  //s=s.replace(/&#(\d+);/g,String.fromCharCode("$1"));//行不通
    4771  var s=this.valueOf().replace(/ /g,' ').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,"'"),m,t;
    4772
    4773  //舊版本
    4774  //if(m=s.match(/&#(\d{2,7});/g))for(var i=0;i<m.length;i++)s=s.replace(m[i],String.fromCharCode(parseInt(m[i].slice(2,-1))));
    4775
    4776  s=s	//.replace(/&#(0*38|[xX]0*26);/g,"\0")	//預防&：&=&
    4777  //	.replace(/�*38;([^\d;]|$)/g,"\0$1").replace(/&#[xX]0*26;?([^a-fA-F\d;]|$)/g,"\0$1")
    4778
    4779  .replace(/�*(\d{2,7});/g,function($0,$1){return String.fromCharCode($1);})	//JScript 5.5~
    4780  //	.replace(/�*(\d{2,7});/g,function($0,$1){return $1>1114111?$0:String.fromCharCode($1);})	//預防error之版本,~10FFFF=1114111
    4781
    4782  //if(mode=='x')
    4783  //.replace(/&#[xX]0*([a-fA-F\d]{2,6});/g,function($0,$1){return String.fromCharCode(parseInt($1,16));})	//$x111;之版本
    4784  //	.replace(/&#[xX]0*([a-fA-F\d]{2,6});/g,function($0,$1){var t=parseInt($1,16);return t>1114111?$0:String.fromCharCode(t);})
    4785
    4786  //.replace(/\0/g,"&")	//預防&回復
    4787  ;
    4788  if(b)s=s.gText();
    4789  return s;
    4790 };
    4791 //	可適用perl: HTML::Entities::encode_entities()
    4792 //	需要escape的: [\<\>\"\'\%\;\)\(\&\+], tr/A-Za-z0-9\ //dc	http://www.cert.org/tech_tips/malicious_code_mitigation.html
    4793 CeL.interact.DOM
    4794 .
    4795 /**
    4796  * Translate HTML code to Unicode text
    4797  * @param {String} HTML	HTML code
    4798  * @param {Boolean} only_digital
    4799  * @returns
    4800  * @memberOf	CeL.interact.DOM
    4801  */
    4802 HTML_to_Unicode=function (HTML, only_digital) {
    4803 	//	使用\0可能會 Warning: non-octal digit in an escape sequence that doesn't match a back-reference
    4804 	var t = HTML.valueOf();
    4805
    4806 	if (!only_digital)
    4807 		t = t
    4808 			//	自動clip null character
    4809 			.replace(/\0\0/g, '')
    4810 			.replace(/ /g, ' ')
    4811 			.replace(/</g, '<')
    4812 			.replace(/>/g, '>')
    4813 			.replace(/"/g, '"')
    4814 			.replace(/'/g, "'")
    4815 			.replace(/®/g, "®")
    4816 			;
    4817
    4818 	t = t
    4819 		//預防&：&=&
    4820 		.replace(/&#(0*38|[xX]0*26);/g, "\0\0")
    4821 		//預防error之版本,~10FFFF=1114111
    4822 		.replace(/�*(\d{2,7});/g, function ($0, $1) { return $1 > 1114111 ? $0 : String.fromCharCode($1); })
    4823 		.replace(/&#[xX]0*([a-fA-F\d]{2,6});/g, function ($0, $1) { var t = parseInt($1, 16); return t > 1114111 ? $0 : String.fromCharCode(t); })
    4824 		;
    4825
    4826 	if (!only_digital)
    4827 		t = t
    4828 			//預防&回復
    4829 			.replace(/\0\0/g, "&")
    4830 			.replace(/&/g, '&')
    4831 			;
    4832
    4833 	return t;
    4834 };
    4835
    4836 CeL.interact.DOM
    4837 .
    4838 /**
    4839  * Translate Unicode text to HTML
    4840  * @param {String} text	Unicode text
    4841  * @param mode	mode='x':&#xhhh;
    4842  * @return {String}	HTML
    4843  * @memberOf	CeL.interact.DOM
    4844  */
    4845 to_HTML=function (text, mode) {
    4846 	var html = '', t, i = 0;
    4847 	for (; i < text.length; i++)
    4848 		t = text.charCodeAt(i), html += '&#' + (mode === 'x' ? 'x' + t
    4849 				.toString(16) : t) + ';';
    4850 	return html;
    4851 };
    4852 CeL.interact.DOM
    4853 .
    4854 /**
    4855  * Translate Unicode text to HTML code
    4856  * @param text	Unicode text
    4857  * @param flags	flags, f&1!=0: turn \t, (f&2)==0: \n→<br/>, f==4: to quoted
    4858  * @param	ignore_tags	e.g., {object:{src:/^https?:\/\//},img:{src:/^https?:\/\//},a:{href:/^https?:\/\//}}
    4859  * @return
    4860  * @memberOf	CeL.interact.DOM
    4861  */
    4862 Unicode_to_HTML=function (text, flags, ignore_tags) {
    4863 	text = ('' + text)
    4864 		.replace(/&/g, '&')
    4865 		//	就是會出現這奇怪情況。
    4866 		.replace(/&amp;/gi, '&')
    4867 		.replace(/>/g, '>')
    4868 		.replace(/"/g, '"')
    4869 		;
    4870
    4871 	if (ignore_tags)
    4872 		text = text.replace(
    4873 		/<([^>]+)>/g,
    4874 		function($0, $1) {
    4875 			if (!($1 in ignore_tags))
    4876 				return '<' + $1;
    4877 			var s = $1.split(/ /), i = 1, l = s.length, c = ignore_tags[$1];
    4878 			for (; i < l; i++) {
    4879 				m = s[i].match(/^([^=]+)(.+?)/);
    4880 				if (!(m[1] in c)
    4881 						|| !(library_namespace.is_type(
    4882 								c[m[1]], 'RegExp')
    4883 								&& c[m[1]].test(m[2]) || library_namespace
    4884 								.is_Function(c[m[1]])
    4885 								&& c[m[1]](m[2])))
    4886 					s[i] = '';
    4887 				return s.join(' ');
    4888 			}
    4889 		});
    4890 	else
    4891 		text = text.replace(/</g, '<');
    4892
    4893 	if (flags == 4) return text;
    4894
    4895 	text = text.replace(/ /g, ' ');
    4896
    4897 	//if(!f)f=0;
    4898 	if (flags & 1)
    4899 		text = text.replace(/	/g, '<span style="margin-left:3em;"> </span>');
    4900 	if (!(flags & 2))
    4901 		text = text.replace(/(\r?\n)/g, '<br/>$1'); //+'<br/>\n';
    4902 	return text;
    4903 };
    4904
    4905 // Ucode:\uhhhh及\xhh之意
    4906 function UcodeToTxt(U) {
    4907 	var T = U.replace(/\\\\|\\u005[cC]|\\x5[cC]|\\134/g, "\0")
    4908 		/*
    4909 		//way 1
    4910 		.replace(/\\u([a-fA-F\d]{4})/g,function($0,$1){return String.fromCharCode(parseInt($1,16));})
    4911 		.replace(/\\x([a-fA-F\d]{2})/g,function($0,$1){return String.fromCharCode(parseInt($1,16));})
    4912 		.replace(/\\([0-7]{1,3})/g,function($0,$1){return String.fromCharCode(parseInt($1,16));})
    4913 		//way 2
    4914 		.replace(/\\(u[a-fA-F\d]{4}|x[a-fA-F\d]{2})/g,function($0,$1){return String.fromCharCode(parseInt($1.substr(1),16));})
    4915 		.replace(/\\([0-7]{1,3})/g,function($0,$1){return String.fromCharCode(parseInt($1,16));})
    4916 		*/
    4917 		//way 3
    4918 		.replace(/\\(u[a-fA-F\d]{4}|x[a-fA-F\d]{2}|[0-7]{1,3})/g, function ($0, $1) { var t = $1.charAt(0); return String.fromCharCode(parseInt(t == 'u' || t == 'x' ? $1.substr(1) : $1, 16)); })
    4919 		;
    4920
    4921 	if (T.indexOf("\\") != -1)
    4922 		T = T
    4923 			.replace(/\\t/g, "<Tab>")
    4924 			.replace(/\\n/g, "<Line Feed>")
    4925 			.replace(/\\v/g, "<Vertical Tab>")
    4926 			.replace(/\\f/g, "<Form Feed>")
    4927 			.replace(/\\r/g, "<Carriage Return>")
    4928 			.replace(/\\(.)/g, "$1");
    4929
    4930 	return T.replace(/\0/g, "\\");
    4931 }
    4932 function TxtToUcode(T, l) {
    4933 	var i = 0, U = '', t;
    4934 	if (!l) l = 0;
    4935 	for (; i < T.length; i++)
    4936 		U += (t = T.charCodeAt(i)) < l ? T.charAt(i) :  "\\u0000".substr(0, 6 - (t = t.toString(16)).length) + t;
    4937 	return U;
    4938 }
    4939 function CSSToTxt(C) {
    4940 	return C.replace(/\\\\|\\0{0,4}5[cC][ \t\r\n\f]?/g, "\0")
    4941 		.replace(/\\([a-fA-F\d]{1,6})[ \t\r\n\f]?/g, function ($0, $1) { return String.fromCharCode(parseInt($1, 16)); })
    4942 		.replace(/\\(.)/g, "$1").replace(/\0/g, "\\");
    4943 }
    4944 function TxtToCSS(T, r, sp) {
    4945 	//	r:radio,sp:separator
    4946 	var i = 0, C = '', t, p = r && r > 3 && r < 9 ? '0'.x(r - 1) : '';
    4947 	if (!sp) sp = ''; sp += '\\';
    4948
    4949 	for (; i < T.length; i++)
    4950 		t = T.charCodeAt(i).toString(16)
    4951 		, C += sp + p.substr(0, r - t.length) + t; //(p&&r>t.length?p.substr(0,r-t.length):''):如果length是0或負值，會傳回空字串。
    4952 	return C.slice(sp.length - 1);
    4953 }
    4954
    4955
    4956 CeL.interact.DOM
    4957 .
    4958 /**
    4959  * Translate a query string to a native Object contains key/value pair set.
    4960  * @param	{String} query_string	query string. default: location.search
    4961  * @param	{Object} add_to	append to this object
    4962  * @return	key/value pairs
    4963  * @type	Object
    4964  * @since	2010/6/16 15:18:50
    4965  * @memberOf	CeL.interact.DOM
    4966  * @see
    4967  */
    4968 get_query = function(query_string, add_to) {
    4969 	if (!query_string)
    4970 		query_string = window/* self */.location.search.slice(1);
    4971 	// else if(typeof query_string!=='string')..
    4972
    4973 	var i, q = query_string.replace(/\+/g, ' ').split('&'), p, s = add_to || {}, k, v;
    4974 	for (i in q)
    4975 		try {
    4976 			if (p = q[i].match(/^([^=]*)=(.*)$/)) {
    4977 				k = decodeURIComponent(p[1]);
    4978 				v = decodeURIComponent(p[2]);
    4979 				if (k in s)
    4980 					if (typeof s[k] === 'string')
    4981 						s[k] = [ s[k], v ];
    4982 					else
    4983 						s[k].push(v);
    4984 				else
    4985 					s[k] = v;
    4986 			} else
    4987 				s[decodeURIComponent(q[i])] = undefined;
    4988 		} catch (e) {
    4989 			// TODO: handle exception
    4990 		}
    4991
    4992 	return s;
    4993 };
    4994
    4995
    4996 CeL.interact.DOM
    4997 .
    4998 /**
    4999  * Translate a native Object contains key/value pair set to a query string.
    5000  * TODO
    5001  * @param	{Object} query_Object	query Object.
    5002  * @return	{String} query string
    5003  * @type	String
    5004  * @memberOf	CeL.interact.DOM
    5005  * @see
    5006  * jQuery.param
    5007  */
    5008 to_query_string = function(query_Object) {
    5009 	;
    5010 };
    5011
    5012 /*	簡化 HTML (word)
    5013 	simplify HTML
    5014 	目標：剩下語意部分，去掉 style。
    5015 TODO:
    5016 保留 b, em
    5017 */
    5018
    5019 //	保留 color: return style string to add
    5020 //reduceHTML.keep_color=
    5021 reduceHTML._keep_color =
    5022 	function (c) {
    5023 		if (c !== 'black')
    5024 			return c;
    5025 	};
    5026 reduceHTML.file = function (FP, enc) {
    5027 	//sl('reduceHTML [' + FP + ']');
    5028 	var t = simpleRead(FP, enc || simpleFileAutodetectEncode), l;
    5029 	if (!t) {
    5030 		err('Open [' + FP + '] failed.');
    5031 		return;
    5032 	}
    5033
    5034 	l = t.length;
    5035 	t = this(t);
    5036
    5037 	FP = FP.replace(/\.s?html?$/i, function ($0) { return '.reduced' + $0; });
    5038 	//sl('reduceHTML: ' + l + '→' + t.length + ' (' + parseInt(100 * t.length / l) + '%)' + ', save to [<a href="' + encodeURI(FP) + '">' + FP + '</a>].');
    5039 	simpleWrite(FP, t, 'utf-8');
    5040 };
    5041 function reduceHTML(t) {
    5042 	if (!t)
    5043 		return;
    5044 	var _f = reduceHTML, f = function($0, $1, $2) {
    5045 		return $1 != $2 || ($1.toLowerCase() in {
    5046 			a : 1,
    5047 			p : 1,
    5048 			head : 1
    5049 		}) ? $0 : '';
    5050 	};
    5051 	//if(m=t.match(/<!--\[if [^\]]+\]>(.|\n)*?<!\[endif\]-->/))sl(m[0].replace(/</g,'<'));
    5052 	//if(m=t.match(/<!\[if !vml\]>((.|\n)*?)<!\[endif\]>/))sl(m[0]);
    5053
    5054 	t = t
    5055 		.replace(/[\s\n]*<(t[dh])([^>]+)>[\s\n]*/ig, function ($0, $1, $2) { var a = $2.match(/[\s\n](col|row)span=['"]?\d{1,3}['"]?/ig); return '<' + $1 + (a ? a.join('') : '') + '>'; })
    5056 		.replace(/<\?xml:namespace[^>]+>/g, '')
    5057 		.replace(/[\s\n]*(<\/t[dh]>)[\s\n]*/ig, '$1')
    5058 		.replace(/<wbr([^>]*)>/ig, '<br/>')
    5059 		.replace(/<([bh]r)[\s\n]+([^>]*)\/?>/ig, function ($0, $1, $2) { var m = $2.match(/[\s\n;"'][\s\n]*page-break-before[\s\n]*:[\s\n]*([^\s\n;"']+)/); return '<' + $1 + (m ? ' style="page-break-before:' + m[1] + '"' : '') + '>'; })
    5060 		.replace(/<(span|font|p|div|b|u|i)[\s\n]+([^>]*)>/ig, function ($0, $1, $2) {
    5061 			var t = '<' + $1, s = '', m;
    5062 			if (
    5063 					//	/Italic/i.test($2)
    5064 					$2.indexOf('Italic') !== -1)
    5065 				s += 'font-style:italic;';
    5066 			//	TODO: <u>, <b>
    5067 			if (_f.keep_color && (m = $2.match(/[\s\n;"'][\s\n]*color[\s\n]*:[\s\n]*([^\s\n;"']+)/)) && (m = _f.keep_color(m[1])))
    5068 				//	保留 color
    5069 				s += 'color:' + m + ';';
    5070 			return t + (s ? ' style="' + s + '"' : '') + '>';
    5071 		})
    5072 		.replace(/<(tr|table)[\s\n]+([^>]*)>/ig, '<$1>')
    5073 		.replace(/<span>((.|\n)*?)<\/span>/ig, '$1')	//	不能用 .+|\n ，IE8 sometimes crash
    5074 		.replace(/<span>((.|\n)*?)<\/span>/ig, '$1')	//	need several times
    5075 		.replace(/<font>((.|\n)*?)<\/font>/ig, '$1')
    5076 		.replace(/<([a-z\d]+)>[\s\n]*<\/([a-z\d]+)>/ig, f)
    5077 		.replace(/<([a-z\d]+)>[\s\n]*<\/([a-z\d]+)>/ig, f)	//	2 times
    5078 		.replace(/<o:p>((.|\n)*?)<\/o:p>/ig, '$1')
    5079 		.replace(/<st1:[^>]+>((.|\n)*?)<\/st1:[^>]+>/ig, '$1')
    5080 		.replace(/<!\[if !vml\]>((.|\n)*?)<!\[endif\]>/ig, '$1')
    5081 		.replace(/<o:SmartTagType [^>]+\/>/ig, '')
    5082 		/*
    5083 		<td>
    5084 		<p> </p>
    5085 		</td>
    5086 		*/
    5087 		.replace(/<(span|p|div|t[dr])([^>]*>)<(span|p)>(([\s\n]+| )*?)<\/(span|p)><\/(span|p|div|t[dr])>/ig, '<$1$2$4</$7>')
    5088 		.replace(/<link rel=(File-List|colorSchemeMapping|themeData|Edit-Time-Data)[^>]+>/ig, '')
    5089 		.replace(/^\s*<html[^>]*>(\r?\n)*/, '<html>')
    5090 		.replace(/(\r?\n)*<body[^>]+>(\r?\n)*/, '<body>')
    5091 		.replace(/(\r?\n)*<!--\[if [^\]]+\]>(.|\n)*?<!\[endif\]-->(\r?\n)*/ig, '')
    5092 		.replace(/(\r?\n)*<style[^>]*>(.|\n)*?<\/style>(\r?\n)*/ig, '')
    5093 		.replace(/(\r?\n)*<meta[\s\n][^>]+>(\r?\n)*/ig, '')
    5094
    5095 		//	from HTML_to_Unicode()
    5096 		.replace(/�*(\d{2,7});/ig, function ($0, $1) { return $1 > 1114111 ? $0 : String.fromCharCode($1); })	//預防error之版本,~10FFFF=1114111
    5097 		.replace(/([\s\n]+| )+$|^([\s\n]+| )+/g, '')
    5098 		;
    5099
    5100 	if (/<table[\s>\r\n]/.test(t))
    5101 		//sl('Has table'),
    5102 		t = t.replace(/<\/head>/i, '<style type="text/css">table,th,td{border:1px solid #888;border-collapse:collapse;}</style></head>');
    5103
    5104 	return t;
    5105 };
    5106
    5107
    5108 CeL.interact.DOM
    5109 .
    5110 /**
    5111  * 將 BIG5 日文假名碼修改為 Unicode 日文假名。
    5112  * @param {String} text	Unicode text
    5113  * @return
    5114  * @see
    5115  * from Unicode 補完計畫 jrename.js
    5116  */
    5117 Big5_kana_fix = function(text) {
    5118 	var H = '', t, i = 0;
    5119 	for (; i < text.length; i++)
    5120 		t = c.charCodeAt(0)
    5121 		// 某次破解Windows Installer所用的資料
    5122 		// ,H+=String.fromCharCode(t>61300?t-48977:t);
    5123 		, H += t === 63219 ? 'ー' : String.fromCharCode(
    5124 				// ひらがな
    5125 				t >= 63223 && t <= 63305 ? t - 50870 :
    5126 				// カタカナ
    5127 				t >= 63306 && t <= 63391 ? t - 50857 :
    5128 				// text.charAt(i);
    5129 				t);
    5130 	return H;
    5131 };
    5132
    5133
    5134 //	↑for string encoding	-----------------------------------------------
    5135
    5136
    5137
    5138
    5139 return (
    5140 	CeL.interact.DOM
    5141 );
    5142 }
    5143
    5144
    5145 });
    5146
    5147