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