UNPKG

cejs

Version:

A JavaScript module framework that is simple to use.

1,607 lines (1,467 loc) 294 kB
/** * @name CeL function for World Wide Web (www, W3) * @fileoverview 本檔案包含了 www 的 functions。 * * <code> http://www.comsharp.com/GetKnowledge/zh-CN/It_News_K902.aspx http://www.nczonline.net/blog/2010/01/12/history-of-the-user-agent-string/ 當 IE 初次推出它們的 User Agent 標誌的時候,是這個樣子: MSIE/3.0 (Win95; U) TODO: don't use .innerHTML 通盤確認所有 HTMLElement 變數已經設成 null 功能探測 vs 瀏覽器探測 http://www.comsharp.com/GetKnowledge/zh-CN/It_News_K987.aspx Mark Pilgrim 有一個清單,它可以讓你探測任何功能。 http://diveintohtml5.org/everything.html JQuery LazyLoad實現圖片延遲加載-探究 - jackchain - 博客園 http://www.cnblogs.com/qidian10/archive/2011/08/17/2143081.html JavaScript & images LazyLoad 图片延迟加载(伪lazyload) - I'm qiqiboy ! http://www.qiqiboy.com/2011/04/12/javascript-and-images-lazyload.html 改造jQuery lazyLoad插件_ 前端開發_ JavaScript http://www.popo4j.com/qianduan/transformation_jquery_lazyload_plug.html 在圖片尺寸比較大的情況下,圖片加載較慢,因此請求會被攔截,並且保留客戶端數據,在下次Img標籤加載Load方法的時候,可以繼續請求圖片數據 </code> * * @since */ 'use strict'; // 'use asm'; // -------------------------------------------------------------------------------------------- // 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。 typeof CeL === 'function' && CeL.run({ // module name name : 'interact.DOM', // data.code.compatibility.trim require : 'data.code.compatibility.' + '|data.code.|data.native.' // + '|data.split_String_to_Object' // + '|application.locale.gettext', // 設定不匯出的子函式。 // no_extend : '*', // 為了方便格式化程式碼,因此將 module 函式主體另外抽出。 code : module_code }); function module_code(library_namespace) { var module_name = this.id, // requiring split_String_to_Object = this.r('split_String_to_Object'), gettext = this .r('gettext'); /** * null module constructor * * @class web 的 functions */ var _// JSDT:_module_ = function() { // null module constructor }; /** * for JSDT: 有 prototype 才會將之當作 Class */ _// JSDT:_module_ .prototype = {}; // HTML only ------------------------------------------------------- // https://stackoverflow.com/questions/50840168/how-to-detect-if-the-os-is-in-dark-mode-in-browsers // https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia if (library_namespace.is_WWW(true) && window.matchMedia) { // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme // or: @media (prefers-color-scheme: light) { body { ... } } if (window.matchMedia('(prefers-color-scheme: dark)').matches) { // CeL.DOM.navigator_theme _.navigator_theme = 'dark'; } else if (window.matchMedia('(prefers-color-scheme: light)').matches) { _.navigator_theme = 'light'; } else { // _.navigator_theme = 'no-preference'; } } /** * NodeType: const unsigned short. * * @see http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-1950641247 * http://www.w3.org/TR/DOM-Level-2-Core/core.html * 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 * @inner */ var ELEMENT_NODE = 1, // TEXT_NODE = 3, // DOCUMENT_NODE = 9; if (library_namespace.is_WWW(true) && // IE8: undefined !isNaN(document.ELEMENT_NODE)) ELEMENT_NODE = document.ELEMENT_NODE, TEXT_NODE = document.TEXT_NODE, DOCUMENT_NODE = document.DOCUMENT_NODE; // w3.org namespaces base var W3C_BASE = 'http://www.w3.org/'; if (!W3C_BASE.startsWith('http')) { /** * 修改以適應 web.archive.org. Under archive.org, it will change to something * like '/web/20140814093917/http://www.w3.org/'. */ W3C_BASE = W3C_BASE.slice(W3C_BASE.indexOf('http')); } // IE 中 Object.prototype.toString.call(HTML Element)==='[object Object]', 得用 // ''+node var get_object_type = Object.prototype.toString, // element_pattern = /^\[object HTML([A-U][A-Za-z]{1,15})?Element\]$/; _// JSDT:_module_ . /** * 判斷是否為 HTML 之 element,包括一般 ELEMENT_NODE 以及 TEXT_NODE。 e.g., object * instanceof HTMLLIElement * * @param object * object to test * @returns {Boolean} object is HTML Element * @since 2010/6/23 02:32:41 * @_memberOf _module_ * @see http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037, * http://www.w3.org/DOM/ */ is_HTML_element = function(object) { var type = get_object_type.call(object); // return type.indexOf('[object HTML') === 0; return element_pattern.test(type) || '[object Text]' === type && object.nodeType === TEXT_NODE; }; _// JSDT:_module_ . /** * 判斷為指定 nodeType 之 HTML Element。 * * @param object * object to test * @param test_type * type to test * @returns {Boolean} object is the type of HTML Element * @since 2010/6/23 02:32:41 * @_memberOf _module_ * @see http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037, * http://www.w3.org/DOM/ */ is_HTML_element_type = function(object, test_type) { var type = get_object_type.call(object); return test_type === TEXT_NODE ? '[object Text]' === type && object.nodeType === TEXT_NODE : object.nodeType === test_type && (test_type === DOCUMENT_NODE || element_pattern .test(type)); }; _// JSDT:_module_ . /** * 判斷是否為 DOM node。<br /> * 包含 TEXT_NODE, DOCUMENT_NODE, SVG element 等。 * * @param object * object to test * @returns {Boolean} object is DOM node * @since 2014/11/4 18:40:30 * @_memberOf _module_ * @see http://www.w3.org/DOM/ */ is_DOM_NODE = function(object) { return object // && object.nodeType > 0 && object.nodeType === (object.nodeType | 0) // SVG element 無 .getElementById(),有 .getElementsByTagName()。 // IE8 無 .getElementsByTagName()。 // && typeof object.getElementsByTagName === 'function'; && ('nextSibling' in object); }; _// JSDT:_module_ . /** * 判斷是否為 <a * href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node-ELEMENT_NODE">ELEMENT_NODE</a>。<br /> * 不包含 TEXT_NODE, DOCUMENT_NODE 等。 * * @param object * object to test * @returns {Boolean} object is HTML Element * @since 2010/6/23 02:32:41 * @_memberOf _module_ * @see http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-58190037, * http://www.w3.org/DOM/ */ is_ELEMENT_NODE = function(object) { if (false) library_namespace .debug('Test ' + get_object_type.call(object) + ' ' + ((typeof object === 'object' || typeof object === 'function') && object.nodeType || '') + ': ' + element_pattern .test(get_object_type.call(object)) + ',' + (object.nodeType === 1)); return element_pattern.test(get_object_type.call(object)) && object.nodeType === ELEMENT_NODE; }; // IE8: [object Object] var DOCUMENT_TYPE = library_namespace.is_WWW() && get_object_type.call(document) || '[object HTMLDocument]'; _// JSDT:_module_ .is_DOCUMENT_NODE = function(object) { // element_pattern 不能用在 DOCUMENT_NODE。 // return _.is_HTML_element_type(object, DOCUMENT_NODE); if (false && object) library_namespace.debug('type: ' + get_object_type.call(object) + ', nodeType=' + object.nodeType); return get_object_type.call(object) === DOCUMENT_TYPE && object.nodeType === DOCUMENT_NODE; }; _// JSDT:_module_ . /** * 判斷是否為 <a * href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-536297177">NodeList</a>。<br> * * @param object * object to test * @returns {Boolean} if is NodeList * @since 2012/3/4 * @_memberOf _module_ * @see http://stackoverflow.com/questions/7238177/detect-htmlcollection-nodelist-in-javascript<br /> * http://www.webdeveloper.com/forum/showthread.php?t=239887 */ is_NodeList = function(object) { var type = get_object_type.call(object); return type === '[object NodeList]' // 依2012現行實作,部分 browser 對 .getElementsByTagName() 之類所得為 NodeList。 // https://developer.mozilla.org/en-US/docs/DOM/element.getElementsByTagName // http://www.w3.org/TR/domcore/#dom-document-getelementsbytagname || type === '[object HTMLCollection]'; }; // &nbsp; \u00a0 var NBSP = '\xa0'; _.NBSP = NBSP; if (false) string = string.replace(/ /g, CeL.DOM.NBSP); /** * <code> debug 用。 IE5DOM @ IE9 test: IE7DOM @ IE9 test: node <DIV>: type object, toString.call: [object Object], ""+node: [object], nodeType: 1: IE8: IE8DOM @ IE9 test: IE9DOM @ IE9 test: node <DIV>: type object, toString.call: [object Object], ""+node: [object HTMLDivElement], nodeType: 1: IE8: node <A>: type object, toString.call: [object Object], ""+node: , nodeType: 1: node <OBJECT>: type object, toString.call: [object Object], ""+node: [object], nodeType: 1: </code> */ function show_node(node) { var type = get_object_type.call(node); if (_.is_NodeList(node)) { library_namespace.debug(node.length + ' node list ' + type + ': ' + node[0] + '...', 1, 'show_node'); } else if (_.is_ELEMENT_NODE(node)) { library_namespace.debug('node' // + (node.tagName ? ' &lt;' + node.tagName // + (node.id ? '#' + node.id : '') + '&gt;' : '') // + ': type ' + typeof node + ', toString.call: ' + type // + ', ""+node: ' + ('' + node) + ', nodeType: ' + node.nodeType // + ('outerHTML' in node ? ': ' + node.outerHTML // : 'innerHTML' in node ? ': ' + node.innerHTML : ''), // 1, 'show_node'); } else { library_namespace .debug( type + (node && typeof node === 'object' ? '.nodeType = ' + node.nodeType + (node.nodeType === DOCUMENT_NODE ? ' (DOCUMENT_NODE)' : '') : ''), 1, 'show_node'); if (node.nodeType === DOCUMENT_NODE) { library_namespace.debug('wondow.document.body: [' + node.body.innerHTML.replace(/</g, '&lt;') + ']', 3, 'show_node'); } } } if (library_namespace.is_WWW()) { (function() { try { // workaround for IE, 因用 General type, 效能較差 var d = window.document.createElement('div'), s; if (false) alert('toString test: ' + element_pattern.test(get_object_type.call(d))); if (d.nodeType !== ELEMENT_NODE) { // doesn't support W3C DOM? throw 0; } try { // IE8 中使用 d.getElementsByName('n') 會失效,_.is_NodeList(s) === // true。 s = d.getElementsByTagName('div'); if (!_.is_NodeList(s) && get_object_type.call(s) === '[object Object]') { // IE 6-8 _.is_NodeList = function(object) { try { return object && '[object Object]' === get_object_type .call(object) // IE9 的相容Quirks模式中可能符合 NodeList 的條件,但卻為 // ELEMENT_NODE.. && !object.tagName // function or object && typeof object.item !== 'undefined' && !isNaN(object.length) // use NodeList(index), e.g., // `object(0)`, // may throw. && (object.length > 0 ? _ .is_HTML_element(object[0]) : object[0] === null); } catch (e) { } }; } } catch (e) { // TODO: handle exception } s = element_pattern.test(get_object_type.call(d)); if (!s) { if (element_pattern.test('' + d)) // e.g., IE 9 _.is_HTML_element = function(object) { return object && (element_pattern.test('' + object) // for IE8. object 可能是 null! || typeof object === 'object' // && object.tagName === "OBJECT" && object.nodeType === ELEMENT_NODE && "[object NamedNodeMap]" === '' + object.attributes); }; else if (get_object_type.call(d) === '[object Object]') { // e.g., IE 5-8. 這種判別方法有漏洞! _.is_HTML_element = function(object) { return get_object_type.call(object) === '[object Object]' // object !== null, undefined && object && typeof object.nodeType === 'number'; }; // bug fix/workaround for IE8: // IE8 中 CeL.is_Object(ELEMENT_NODE) === true! _.is_Object = function(object) { return get_object_type.call(object) === '[object Object]' // object !== null, undefined && object // test a readonly property && typeof object.nodeType !== 'number'; }; } else throw 1; // General type _.is_HTML_element_type = function(object, type) { return _.is_HTML_element(object) && object.nodeType === type; }; _.is_ELEMENT_NODE = function(object) { return _.is_HTML_element(object) && object.nodeType === ELEMENT_NODE; }; } } catch (e) { // TODO: handle exception } finally { d = null; } })(); } /** * <code> test if can use flash better use SWFObject: http://code.google.com/p/swfobject/ Browser detect: http://www.quirksmode.org/js/detect.html var plugin=(window.navigator.mimeTypes && window.navigator.mimeTypes["application/x-shockwave-flash"]) ? window.navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0; if ( plugin ) { plugin=parseInt(plugin.description.substring(plugin.description.indexOf(".")-1)) >= 3; } else if (window.navigator.userAgent && window.navigator.userAgent.indexOf("MSIE")>=0 && window.navigator.userAgent.indexOf("Windows")>=0) { document.write('<SCRIPT LANGUAGE=VBScript\> \n'); document.write('on error resume next \n'); document.write('plugin=( IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.6")))\n'); document.write('<\/SCRIPT\> \n'); } if ( plugin ) { document.write('<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'); document.write(' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" '); document.write(' ID=flash5clickTAG WIDTH='+n_width+' HEIGHT='+n_height+'>'); document.write(' <PARAM NAME=movie VALUE="'+ n_flashfile +'"><param name=wmode value=opaque><PARAM NAME=loop VALUE=true><PARAM NAME=quality VALUE=high> '); document.write(' <EMBED src="'+ n_flashfile +'" loop=true wmode=opaque quality=high '); document.write(' swLiveConnect=FALSE WIDTH='+n_width+' HEIGHT='+n_height+''); document.write(' TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">'); document.write(' <\/EMBED>'); document.write(' <\/OBJECT>'); } else if (!(window.navigator.appName && window.navigator.appName.indexOf("Netscape")>=0 && window.navigator.appVersion.indexOf("2.")>=0)){ document.write('<A HREF="'+ n_altURL +'" target="'+n_target+'"><IMG SRC="'+ n_altimg +'" WIDTH='+n_width+' HEIGHT='+n_height+' BORDER=0><\/A>'); } </code> */ // copy from base.js // window.onerror=HandleError; function HandleError(message, url, line) { // if(window.confirm())_DO_CONTINUE_ if (window.navigator.appName == "Microsoft Internet Explorer") return !window.confirm(url + '\n\nJavaScript Error: ' + line + '\n' + message + '\n\nSee more details?'); else if (window.navigator.appName == "Netscape") // document.location.href="javascript:"; window.navigate('javascript:'); /** <code>'Warning: function HandleError does not always return a value' in some Firebird with user_pref("javascript.options.strict", true); @ prefs.js</code> */ // return message; } // 預防(舊版)NS resize時版面亂掉 // window.onresize=OnResize; function OnResize() { // 回上一頁 history.go(-1),history.back()/history.forward() // this.location.replace(document.referrer) // Opera's document.referrer returns only null if referrer logging is // disabled // location.replace(),location.reload() history.go(0); } /** * <code> IE only!! http://blog.livedoor.jp/dankogai/archives/50952477.html DOM時代のdocument.write() if (typeof document == 'object') write = document.write; </code> */ /** * <code> http://blog.taragana.com/index.php/archive/how-to-enable-windowstatus-in-firefox/ window.status在firefox下默認是不能修改的。 可以通過工具→選項→網頁特性→啟用javascript→高級→把修改狀態欄文本打上勾就好了。 Open about:config in browser and search for dom.disable_window_status_change. Change it to false. Additionally in Firefox v1.0, this can be changed via "Tools → Options → Web Features → Enable JavaScript / Advanced → Allow scripts to change status bar text" In Firefox v1.5, this can be changed via "Tools → Options → Content → Enable JavaScript / Advanced → Allow scripts to change status bar text" via MozillaZine; learnt the hard way. </code> */ /** * 滾動 window.status * * @param message * @param {Number} * speed 速度 * @param from * from where(基本上勿設定) * @param roll_status_length * unit length(基本上後兩者勿設定) */ function roll_status(message, speed, from, roll_status_length) { // 間隔以 s var s = ' '; if (!roll_status_length) roll_status_length = message.length, message += s + message; if (!from || from >= roll_status_length + s.length) from = 0; if (!message) if (typeof window.status === 'string') roll_status(window.status, speed); else return; else if (message.slice(from) != window.status && message.length > L) return; if (isNaN(speed) || speed > 999) speed = 999; else if (speed < 0) speed = 0; // L:least length var L = 99; while (message.length < L) message += s + message; window.status = message.slice(++from); roll_statusS = window.setTimeout('roll_status("' + message + '",' + speed + ',' + from + ',' + roll_status_length + ');', speed); if (false) roll_statusS = window.setInterval('roll_status("' + message + '",' + speed + ',' + from + ')', speed); } // ↑copy from base.js /** * 預防hack:禁止鍵盤keyboard&滑鼠mouse輸入,可以再加上一層div於最上方以防止copy<br /> * 下面一行調到檔案頭<br /> * var disabledKM = 0; */ // disableKM[generateCode.dLK] = 'disabledKM'; // s=1:回復,s=2:使螢幕亦無法捲動(對NS無效),m:message,輸入時發出警告 function disableKM(s, m) { if (false) { window.onerror = function() { return ture; }; // 定義亦可用 function document.onmousedown(){...} document.onmousedown = document.oncontextmenu = document.onselectstart = document.ondragstart = function( e) { return false; }; // 印刷を禁止して 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"; } } }; window.onafterprint = function() { for (i = 0; i < document.all.length; i++) { if (document.all[i].id == "elmid") { document.all[i].style.visibility = ""; } } }; } if (!document.body) return; if (typeof s == 'undefined') s = 1; if (typeof disabledKM == 'undefined') disabledKM = 0; if (!s) { if (disabledKM) { window.ondragstart = document.body.Oondragstart || null, window.oncontextmenu = document.body.Ooncontextmenu || null, window.onselectstart = document.body.Oonselectstart || null; if (disabledKM == 2) document.body.style.overflow = typeof document.body.Ooverflow == 'string' ? document.body.Ooverflow : 'auto'; window.onmousedown = window.Oonmousedown || null, window.onkeydown = window.Oonkeydown || null; window.onmousedown = document.Oonmousedown || null, window.onkeydown = document.Oonkeydown || null; } disabledKM = 0; return; } if (disabledKM) { // 已lock時不執行多餘的動作與覆蓋舊資訊 if (s == 2) document.body.style.overflow = 'hidden'; else if (typeof document.body.Ooverflow == 'string') document.body.style.overflow = document.body.Ooverflow; } else { // <body oncontextmenu="return false" ondragstart="return false" // onselectstart="return false"> // 預防hack // 使body填滿視窗 // leftMargin=topMargin=rightMargin=bottomMargin=0; document.body.Ooverflow = document.body.style.overflow; if (s == 2) // 使螢幕亦無法捲動 document.body.style.overflow = 'hidden'; if (typeof window.onselectstart != 'undefined') document.body.Oonselectstart = window.onselectstart; if (typeof window.oncontextmenu != 'undefined') document.body.Ooncontextmenu = window.oncontextmenu; if (typeof window.ondragstart != 'undefined') document.body.Oondragstart = window.ondragstart; window.ondragstart = window.oncontextmenu = window.onselectstart = function() { return false; }; // 不要在 document 对象中设置 expando 属性,在 window 对象上设置 expando 属性。 if (typeof window.onmousedown != 'undefined') document.Oonmousedown = window.onmousedown; if (typeof window.onkeydown != 'undefined') document.Oonkeydown = window.onkeydown; // ndblclick= if (typeof document.onmousedown != 'undefined') document.Oonmousedown = document.onmousedown; if (typeof document.onkeydown != 'undefined') document.Oonkeydown = document.onkeydown; } window.onmousedown = window.onkeydown = document.onmousedown = document.onkeydown = document.onContextMenu = new Function( 'e', 'if(window.navigator.appName=="Microsoft Internet Explorer"&&event.button!=1||window.navigator.appName=="Netscape"&&e.which!=1){' + (m ? 'alert(' + dQuote(m) + ');' : '') + 'return false;}'); if (false) { window.captureEvents(Event.MOUSEUP | Event.MOUSEDOWN); window.onmousedown = function(e) { if (e.which == 1) { window.captureEvents(Event.MOUSEMOVE); window.onmousemove = rf; } }; window.onmouseup = function(e) { if (e.which == 1) { window.releaseEvents(Event.MOUSEMOVE); window.onmousemove = null; } }; } // Navigator 4.0x // http://topic.csdn.net/t/20020125/13/498661.html if (!disabledKM && window.Event && window.captureEvents) window.captureEvents(Event.MOUSEDOWN), window .captureEvents(Event.KEYDOWN); disabledKM = s; } if (false) { simpleWrite('a.txt', reduce_code([ f, toggle, library_namespace.set_Object_value ])); for ( var i in style) tt += i + '=' + document.getElementById("others").style[i] + "<br />"; document.write(tt); } /** * 切換(顯示/隱藏) node.<br /> * toggle/swap display and visibility.<br /> * display:none or visibility:hidden. * * TODO: use element.classList.toggle(className); TODO: use computed style * * @param element * HTML element * @param {String|Number}type * show or hidden or set the status type: {Number} type: 0: * hidden(→none), 1: show(→block), 2||undefined: switch, others: * get status only with no change {String} type: set CSS: display * type: none, '', block, inline, list-item. 其他恐造成 error? * @return display status * @since 2010/4/1 10:24:43 refactoring 重構 * @see http://www.w3schools.com/CSS/pr_class_visibility.asp * http://www.w3schools.com/css/pr_class_display.asp * http://www.javaeye.com/topic/140784 * 通過element.style對象只能取得內聯的樣式,也就是說只能取得html標籤裡寫的屬性。 * @requires [get_element],[_.get_style] * @_memberOf _module_ */ function toggle_display(element, type) { // showObj(element); if (!(element = get_element(element))) return; // Opera 7.5 意外的沒有 tagName (-_-) 而 Firefox 也可能沒有此 property. var tagName = ('' + element.tagName).toLowerCase(), style = element.style, v_value = { visible : 1, hidden : 2, collapse : 3 }; if (typeof type === 'undefined' || type == 2) type = style ? (_.get_style ? _.get_style(element, 'display') : // style.display === '' 時預設為顯示 style.display) === 'none' : element.visibility !== 'visible'; if (typeof type === 'boolean') type = type ? 1 : 0; if (!isNaN(type)) // 對各種不同的 tag 作個別設定。 type = type == 0 ? style ? 'none' : tagName === 'tr' ? 'collapse' : 'hidden' : type == 1 ? style ? (tagName in { div : 1, iframe : 1 }) ? 'block' : 'inline' : 'visible' : null; library_namespace.debug('type: ' + type, 2, 'toggle_display'); // test .innerHTML if (false) library_namespace.debug('set display style of &lt;' + tagName + '&gt; to [' + type + ']'); if (style) style[type in v_value ? 'visibility' : 'display'] = type; else if ((type in v_value) // &&!(tagName in {'iframe':1,'input':1}) ) element.visibility = type; else return; return type; } _// JSDT:_module_ .toggle_display = toggle_display; /** * replace HTML * * @param node * @param html * @return * * <code> http://blog.stevenlevithan.com/archives/faster-than-innerhtml You can use the above as el = replace_HTML(el, newHtml) instead of el.innerHTML = newHtml. .innerHTML=,document.createElement(→XML_node() .innerHTML='' → remove_all_child http://forum.moztw.org/viewtopic.php?t=17984&postdays=0&postorder=asc&start=15 adoptNode() 會把現有的節點拿去用,ownerDocument 會被變更,被 adopt 的節點會從原來的 document 消失。 importNode() 比較像是 cloneNode() 加上變更 ownerDocument。 以前因為 Gecko 沒有太嚴格,所以可以用 Ajax 取回一個 XML 文件並直接透過 responseXML 把裡面的節點當 HTML 節點一樣的插入現有的網頁。 </code> * * @_memberOf _module_ */ function replace_HTML(node, html) { if (node && typeof node === 'string') node = document.getElementById(node); if (node && !html && typeof node.replaceChildren === 'function') { // https://developer.mozilla.org/en-US/docs/Web/API/Element/replaceChildren node.replaceChildren(); return node; } // _.is_ELEMENT_NODE(<math>) === false ("[object Element]" @ // Firefox/37.0) if (false) if (!_.is_ELEMENT_NODE(node)) return node; if (!node || !node.innerHTML) return node; try { /** * <code>/* @cc_on // Pure innerHTML is slightly faster in IE node.innerHTML = html || ''; return node; @</code> */ if (false) { var clone = node.cloneNode(false); clone.innerHTML = html || ''; node.parentNode.replaceChild(clone, node); } // 預防之後不知道的 code 還是使用之前的 reference。 node.innerHTML = html || ''; } catch (e) { /** * http://msdn.microsoft.com/en-us/library/ms532998.aspx#TOM_Create * the innerText and innerHTML properties of the table and tr * objects are read-only. */ library_namespace.warn('replace_HTML() error!'); library_namespace.error(e); } // 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. return node; } _// JSDT:_module_ .replace_HTML = replace_HTML; /** * <code> 使用 .firstChild 或 .lastChild 須注意此node可能是 text node,不能 appendChild。須以 .nodeType 判別。 .children[0] (<span>) === .firstElementChild !== .firstChild (maybe #text) http://msdn2.microsoft.com/zh-tw/library/system.xml.xmlnode.removechild(VS.80).aspx 繼承者注意事項 在衍生類別中覆寫 RemoveChild 時,為了要正確引發事件,您必須呼叫基底類別的 RemoveChild 方法。 removeAllChild[generateCode.dLK]='replace_HTML'; function removeAllChild(o){ //return removeNode(o,1); // http://blog.stevenlevithan.com/archives/faster-than-innerhtml if(typeof o=='string')o=document.getElementById(o); if(!o||typeof o!='object')return; o.parentNode.replaceChild(o.cloneNode(false),o); return o; } http://www.webreference.com/js/column43/replace.html 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. node_want_to_replace.removeNode(new_node) </code> */ /** * 移除 node. TODO: also remove event handlers * * @param o * @param tag * tag===1: only child, undefined: remove only self, others: only * <tag> child * @return * @_memberOf _module_ */ function remove_node(o, tag) { var _f = remove_node, i; if (typeof o === 'string') o = document.getElementById(o); if (!_.is_ELEMENT_NODE(o)) return; // remove child if (tag) { if (typeof tag === 'string') tag = tag.toLowerCase(); // safer: if you have any asynchronous events going. But // node.hasChildNodes() will always do an evaluation. // while(o.hasChildNodes()&&(i=o.lastChild))o.removeChild(i); // while(o.hasChildNodes())o.removeChild(o.lastChild); // don't use for() // http://weblogs.macromedia.com/mesh/archives/2006/01/removing_html_e.html // TODO: 直接用 replaceNode 就不用 recursion i = o.childNodes.length; while (i--) if (tag === 1 || _.is_ELEMENT_NODE(o.childNodes[i]) && tag === o.childNodes[i].tagName.toLowerCase()) // _f(o.childNodes[i],tag), // TODO: 會有問題 o.removeChild(o.childNodes[i]); } // remove self // 測試 o.parentNode: 預防輸入的o為create出來的 return tag || !(i = o.parentNode) ? o : i.removeChild(o); } _// JSDT:_module_ .remove_node = remove_node; /** * empty node. CeL.remove_all_childrens */ _// JSDT:_module_ .remove_all_child = _.replace_HTML; /** * set/get/remove attribute of a element<br /> * in IE: setAttribute does not work when used with the style attribute (or * with event handlers, for that matter). * * @param _e * element * @param propertyO * attributes object (array if you just want to get) * @return * @requires split_String_to_Object * @see setAttribute,getAttribute,removeAttribute * http://www.quirksmode.org/blog/archives/2006/04/ie_7_and_javasc.html * @since 2006/12/10 21:25 分離 separate from XML_node() * @_memberOf _module_ */ function set_attribute(_e, propertyO, ns) { _e = get_element(_e); if (!_e || !propertyO // || _e.nodeType === TEXT_NODE ) { return; } var matched, _g, // Namespaces: SVG,MathML,XHTML,XLink _N = new_node.ns; if (typeof propertyO === 'string') { propertyO = /[=:]/.test(propertyO) ? split_String_to_Object(propertyO) : propertyO.split(','); } if (Array.isArray(propertyO)) { _g = propertyO.length === 1 ? propertyO[0] : 1; propertyO = split_String_to_Object(propertyO.join(',')); } for ( var _l in propertyO) { if (_l === 'class' && !propertyO['className']) { propertyO[_l = 'className'] = propertyO['class']; } if (_g || (_l in propertyO) && propertyO[_l] != null) { /** * <code> XML 中id不能以setAttribute設定。 class不能以setAttribute設定@IE。 http://www.quirksmode.org/bugreports/archives/2005/03/setAttribute_does_not_work_in_IE_when_used_with_th.html IE ignores the "class" setting, and Mozilla will have both a "class" and "className" attribute defined </code> */ if ( // _l == 'id' || _l == 'className' || typeof propertyO[_l] == 'function') { if (_g) { propertyO[_l] = _e[_l]; } else { _e[_l] = propertyO[_l]; } } else if (_e.setAttributeNS && (matched = _l.match(/^(.+):([^:]+)$/))) { matched = matched[1]; if (matched.indexOf('://') == -1 && _N[matched.toLowerCase()]) { matched = W3C_BASE + _N[matched.toLowerCase()]; } if (_g) { propertyO[_l] = _e.getAttributeNS(matched, _l); } else { _e.setAttributeNS(matched, _l, propertyO[_l]); if (false) { try { _e.setAttributeNS(matched, _l, propertyO[_l]); } catch (e) { alert('set_attribute: Error!'); } } } } else if (_g) { propertyO[_l] = _e.getAttribute(_l); } else if (false && _e.setAttributeNS) { // TODO: _e.setAttribute(), _e.style.setProperty() _e.setAttributeNS(null, _l, propertyO[_l]); } else { _e.setAttribute(_l, propertyO[_l]); } } } return typeof _g == 'string' ? propertyO[_g] : propertyO; } _// JSDT:_module_ .set_attribute = set_attribute; /** * append children node to specified element * * @param node * node / node id * @param child_list * children node array * @return * @since 2007/1/20 14:12 * @_memberOf _module_ */ function add_node(node, child_list) { var _s = add_node; if ((node = get_element(node)) && arguments.length > 2) { for (var _j = 1, l = arguments.length; _j < l; _j++) _s(node, arguments[_j]); return; } if (!node || !child_list // || node.nodeType === TEXT_NODE ) return; // 預防 RegExp 等,需要 toString() if (library_namespace.is_RegExp(child_list)) child_list = ''; if (typeof child_list === 'object') { if (child_list) if (Array.isArray(child_list) // && child_list.length ) { for (var _j = 0, l = child_list.length; _j < l; _j++) _s(node, child_list[_j]); } else try { // [object SVGTextElement] 亦可 appendChild(). node.appendChild(child_list); } catch (e) { library_namespace.warn('add_node: Cannot insert node!'); // show_node(node); // e.g., 'HIERARCHY_REQUEST_ERR: DOM Exception 3' // e.g., // document.appendChild(document.createElement('div')); // e.g., // document.createTextNode("").appendChild(document.createElement('div')); } return; } if (typeof child_list === 'string' || typeof child_list === 'number' && !isNaN(child_list)) { // child_list = child_list.toString(); _.node_value(node, child_list); } } _// JSDT:_module_ .add_node = add_node; // IE 8 中,使用 (element[p] = text) 無效果,需要使用 (document.title) 設定。 // 並且 document.getElementsByTagName('title')[0].dataset 亦無法取得 dataset。 var need_check_title = library_namespace.is_WWW() && navigator.userAgent.match(/MSIE (\d+)/); set_text.need_check_title = need_check_title = need_check_title && need_check_title[1] < 9; /** * 設定/取得 HTML element 的 text。 * 對付IE與Moz不同的text取得方法。現階段不應用innerText,應該用此函數來取得或設定內部text。 * * @param element * HTML element * @param {String} * text the text to be set * @return * @see http://www.klstudio.com/post/94.html * @_memberOf _module_ */ function set_text(element, text, options) { if (!(element = get_element(element))) return; options = library_namespace.setup_options(options); var text_p = set_text.p; if (typeof text_p !== 'string' || !text_p) set_text.p = text_p // 較新的 browser = typeof document.body.textContent === 'string' ? 'textContent' // e.g., IE : typeof document.body.innerText === 'string' ? 'innerText' // old browsers : 'innerHTML'; var p = typeof element.value === 'string' ? 'value' : text_p; if (typeof text !== 'undefined') { if (need_check_title && element.tagName.toLowerCase() === 'title') document.title = text; else { element[p] = text; if (element.tagName.toLowerCase() === 'input' && options.resize) { var min_width = String(text); min_width = min_width.display_width // CeL.data.native.display_width() ? min_width.display_width() : min_width.length; // 'font-size' is in em. min_width = get_style(element, 'font-size', 'numeral') * (min_width + 1) / 2; if (options.min_width > 0 && !(min_width >= options.min_width)) { min_width = options.min_width; } if (options.max_width > 0 && min_width > options.max_width) { min_width = options.max_width; } if (element.offsetWidth < min_width) set_style(element, 'width', min_width + 'px'); } } } // http://www-128.ibm.com/developerworks/tw/library/x-matters41.html if (element.nodeType === 3 || element.nodeType === 4) // TODO: DOM: 用 element.nodeValue return element.data; // 用 .childNodes if (false) { var s = element.children[0], t = []; if (s) { do { t.push(set_text(s)); } while (s = s.nextSibling); return t.join(''); } } // TODO: fire event var text = element[p]; if (p === 'innerHTML') { // 分斷行 2003/1/25 22:40 // html → text // <.+?> <[^>]+> <\s*\/?\s*[a-zA-Z](.*?)> <! 過慢? text = text // remove <s>...</s>, <del>...</del> .replace(/<(s|del)>[^<]*<\/\1>/gi, '').replace(/<w?br[^>]*>/gi, '\n').replace(/<\/?[A-Za-z][^>]*>/g, ''); } return text; } _// JSDT:_module_ .set_text = set_text; _// JSDT:_module_ .get_node_text = set_text; _// JSDT:_module_ . /** * 自動填寫表單 TODO: cache name if need. * * @param {Object}pairs * 設定 pairs: {id/name: value} * @param {HTMLElement|Object|Integer}config * submit button/form id, {submit: submit button/form id, base: * base space id}. use {} to ignore this argument. */ fill_form = function fill_form(pairs, config) { var name, node, base, submit, event_object, window_object = typeof window === 'object' && window || {}, // 這種 node 需要用到 list 的方法。e.g., checkbox or radio. use_list = function(node) { library_namespace.debug('test &lt;' + node.tagName + ' type="' + node.type + '" name="' + node.name + '" id="' + node.id + '" /&gt;', 2, 'fill_form.use_list'); return _.is_ELEMENT_NODE(node) && node.tagName.toLowerCase() === 'input' && node.type.toLowerCase() in { radio : 1, checkbox : 1 }; }, set_node = function(name) { // if (!name) throw 1; node = base.getElementById(name); library_namespace.debug('.getElementById(' + name + ') = ' + node, 3, 'fill_form.set_node'); // IE9 quirks mode 中, .getElementById() 可以得到 // .getElementsByName()[0]。 if (!node || use_list(node)) { node = base.getElementsByName(name); if (library_namespace.is_debug(2)) { library_namespace.debug('.getElementsByName(' + name + ') = ' + node, 2, 'fill_form.set_node'); show_node(node); } if (!node[0] || !use_list(node[0])) { if (node.length !== 1) { library_namespace.warn('fill_form: 共有 ' + node.length + ' 個 [name=' + name + '] 可供設定' + (node.length ? ',將只設定第一個' : '') + '!'); } node = node[0]; } else { library_namespace.debug( 'treat [name=' + name + '] as checkbox or radio. length = ' + node.length, 2, 'fill_form.set_node'); } } return node; }, fire_event = function(event_id) { // TODO: using event.initEvent() // https://www.webhek.com/apps/you-do-not-need-jquery/#trigger_native if (node[event_id] // 不一定都是 function? // && typeof node[event_id] === 'function' ) { try { // TODO: 完整模擬 DOM event object. // http://msdn.microsoft.com/en-us/library/ms535863(v=vs.85).aspx if (!event_object) { library_namespace.debug('Setup event object for .' + event_id, 2, 'fill_form.fire_event'); event_object = { target : node }; // IE. TODO: 預防所操縱的為 HTA,其 'window' !== 本身之 window。 if ('event' in window_object) { event_object.srcElement = node; try { // 無法設定 window.event: Error 438 [TypeError] // (facility code 10): 物件不支援此屬性或方法. // window_object.event = event_object; // 行不通: window_object.event === null Object .assign(event_object, window_object.event); } catch (e) { } } } library_namespace.debug('Try to fire [' + name + '].' + event_id, 2, 'fill_form.fire_event'); node[event_id].call(node, event_object); } catch (e) { if (library_namespace.is_debug()) { library_namespace .warn('fill_form.fire_event: Error to run [' + name + '].' + event_id + ': ' + node[event_id]); library_namespace.error(e); } } } return fire_event; }, // 模擬鍵盤輸入事件發生。 event_sequence = function(node, value) { fire_event('onfocus')('onclick') // ('onkeydown')('onkeypress') ('oninput') // ('onkeyup') ; library_namespace.debug('Set [' + name + '] = (' + (typeof value) + ') [' + value + ']', 2, 'fill_form.event_sequence'); _.node_value(node, value); fire_event('onpropertychange')('onchange')('onblur'); }; if (library_namespace.is_Object(config)) { submit = config.submit; base = config.base; if (config.window) { window_object = config.window; library_namespace.debug('Setup window: ' + window_object, 2, 'fill_form'); } if (!isNaN(base) && (name = window_object.document.forms[base])) { base = name; } if (config.no_fire) fire_event = function() { return fire_event; }; } if (!_.is_ELEMENT_NODE(base) && !_.is_DOCUMENT_NODE(base)) { library_namespace.debug('Set base to window_object.document.', 2, 'fill_form'); base = window_object.document; } // 確定可以使用 .getElementById。 while (!base.getElementById) { base = base.parentNode; } if (library_namespace.is_debug(2)) { library_namespace.debug('base:', 1, 'fill_form'); show_node(base); } if (library_namespace.is_Object(pairs)) { for (name in pairs) { if (_.is_ELEMENT_NODE(set_node(name))) { event_sequence(node, pairs[name]); } else if (_.is_NodeList(node)) { // <input type="radio|checkbox" value="~" /> for (var i = 0, l = node.length, n, vl = pairs[name], v; i < l; i++) { n = node[i]; // TODO: 若是輸入數字,則有時會強制當作index? v = library_namespace.is_Object(vl) ? vl[n.value] : Array.isArray(vl) ? vl.indexOf(n.value) !== -1 : vl; library_namespace.debug('set value [' + v + '].', 2, 'fill_form'); // n.value 必為 string,v 可能為數字,因此不用 `===`。 if (n.checked !== (typeof v === 'boolean' ? v : v == n.value)) { // 有改變才 fire event。 event_sequence(n, !n.checked); } } } // reset event_object. event_object = undefined; } } if ((node = submit) && (_.is_ELEMENT_NODE(node) || typeof node === 'string' && _.is_ELEMENT_NODE(set_node(node)))) { if (node.tagName.toLowerCase() === 'form') node.submit(); else if (node.click) node.click(); else library_namespace.warn('fill_form: Cannot submit [' + submit + ']'); } else if (!isNaN(submit) && _ .is_ELEMENT_NODE(node = window_object.document.forms[submit])) { fire_event('submit'); } if (config && typeof config.callback === 'function') { config.callback(); } }; _// JSDT:_module_ . /** * 設定 node 之值。 * * @param {HTMLElement}node * 所指定之 node。 * @param {String|Number|Boolean}value * 所要設定之值 * @param {HTMLBodyElement|HTMLElement}base_space * base document/context * @returns node 之值 */ node_value = function node_value(node, value, base_space) { var set_value_list = function(value) { var i, l, v; if (Array.isArray(value)) for (i = 0, l = value.length, v = Object.create(null); i < l; i++) v[value[i]] = true; else if (library_namespace.is_Object(value)) v = value; else (v = Object.create(null))[value] = true; return v; }; if (!node // || !library_namespace.is_WWW() // maybe [object SVGTSpanElement] || !(typeof node === 'string' ? (node = select_node(node, base_space) || get_element(node)) : node)) { if (_.is_NodeList(node) && node.length && 'checked' in node[0]) { if (false) library_namespace.debug('Nodes &lt;' + node[0].tagName + '&gt;[' + node[0].name + '] = ' + value, 1, 'node_value'); // /checkbox|radio/ // var type = node[i].type; for (var i = 0, l = node.length, v = set_value_list(value); i < l; i++) { if (node[i].value in v) { node[i].checked = !!v[node[i].value]; // if (type === 'radio') break; } } } return; } var tag_name = _.is_ELEMENT_NODE(node) ? node.tagName.toLowerCase() : '', type; if (false) library_namespace.debug('Node &lt;' + tag_name + '&gt;', 1, 'node_value'); if ((tag_name in { textarea : 1, select : 1, option : 1 }) || tag_name === 'input' // use only /checkbox|hidden|password|radio|text/ or undefined(default). // .getAttribute('type') && !((type = ('' + node.type).toLowerCase()) in { button : 1, file : 1, image : 1, reset : 1, submit : 1 })) { switch (type) { case 'radio': case 'checkbox': if ('checked' in node) // node.value 必為 string,因此不用 ===。 node.checked = typeof value === 'boolean' ? value : (node.value == value); break; case 'select-multiple': if (Array.isArray(value)) for (var i = 0, options = node.options, l = Math.min( options.length, value.length); i < l; i++) options[i].selected = !!value[i]; else { value = set_value_list(value); for (var i = 0, options = node.options, l = options.length; i < l; i++) { if (options[i].value in v) options[i].selected = !!value[options[i].value]; } } break; // case 'select-one': default: if (false) library_namespace.debug('Use default method to set value.', 1, 'node_value'); if ('value' in node) { if (tag_name === 'select') { // select_node.value → select_node.innerText → // select_node.selectedIndex if (value !== undefined && node.value != value) { node.value = value; } // check if (node.value != value) { // 未設定成功: 沒有此 options.value? var OK; for (var i = 0, options = node.options, l = options.length, v = String( value).trim(); i < l; i++) if (v == options[i].innerHTML.trim()) { node.value = options[i].value; OK = true; break; } if (!OK && !isNaN(value) && value >= 0 && value < node.options.length) { // .options[i].value === value // .selectedIndex= 的設定有些情況下會失效 if (node.selectedIndex != value) { node.selectedIndex = value; // node.onchange && node.onchange(); } } // TODO: alert } else { // node.onchange && node.onchange(); } } else if (value !== undefined && value !== null) { // IE9 的相容Quirks模式中長度使用 'maxLength'. var kw = 'maxLength'; if (!(kw in node)) kw = 'maxlength'; // 因 (''==0),因此若 (value === 0 && node.value === '') // 會出問題。 // 需要先把 value 轉成 string。 value = String(value); if (false) library_namespace.debug('測試是否須截斷過長之設定值 of [' + kw + ']。', 1, 'node_value'); if (!isNaN(node[kw]) // Chrome/68.0.3440.106: // document.createElement('input').maxLength 預設為 -1 && node[kw] >= 0 && value.length > node[kw]) { library_namespace.warn('The length of value [' + value + ']: ' + value.length + ' > limit ' + node[kw] + ' ! I will fill the first ' + node[kw] + ' characters!'); value = value.slice(0, node[kw]); } if (node.value != value) { if (false) library_namespace.debug('Set &lt;' + tag_name + '&gt; = [' + value + ']', 1, 'node_value'); node.value = value; // node.onchange && node.onchange(); } } value = node.value; } else { library_namespace.warn('Cannot set value of node!'); // 需要再處理. .text? // return true; value = node.innerHTML; } } } else if (tag_name === 'option') { if (!node.value) node.value = value; value = node.innerHTML = value; } else if (typeof value === 'string' && value.indexOf('<') !== -1) { // may cause error: -2146827687 未知的執行階段錯誤 e.g., // XML_node('a', 0, 0, [XML_node('a'), '<br />']); // try{ value = node.innerHTML = value; // } catch(e) { node.appendChild(XML_node('span', 0, 0, value)); } } else if (typeof value === 'string' || typeof value === 'number') { _.remove_all_child(node); // try{ node.appendChild(document.createTextNode(value)); value = node.innerHTML; // } catch(e) { alert(e.description); } } else { if (false) alert('node_value: Error insert contents:\n[' + value + ']'); value = node.innerHTML; } return value; }; /** * <code> var alias={ // 'child' || 'c' || '$' || '0' || ... $:'childNode', // class: 'className' || 'c' ... c:'className' s:'style' }; 輸入 ( [{tag1:{attb:attb_val,child:[inner objects]}}, {tag2:{}}, 'br'], insertBeforeO) e.g., ([ { p:[span:'>>test<<'], id:'a', c:'cls', s:{color:'#123'} }, // width:12 === width:'12px' { span:['<<test2>>','text'], s:{color:'',width:12} }, '<<test3>>', {'hr':0}, {'br':0}, { $:tag_name, tag_name:[] }, { tag_ns:0, ns:'http://~' } ], insertSetting) insertSetting: (null) just create & return the n