/** * @name CeL function for World Wide Web (www, W3) * @fileoverview 本檔案包含了 www 的 functions。 * * 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方法的時候,可以繼續請求圖片數據 * * @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。
* 包含 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_ . /** * 判斷是否為 ELEMENT_NODE
* 不包含 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_ . /** * 判斷是否為 NodeList
* * @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
* 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]'; }; //   \u00a0 var NBSP = '\xa0'; _.NBSP = NBSP; if (false) string = string.replace(/ /g, CeL.DOM.NBSP); /** * debug 用。 IE5DOM @ IE9 test: IE7DOM @ IE9 test: node
: type object, toString.call: [object Object], ""+node: [object], nodeType: 1: IE8: IE8DOM @ IE9 test: IE9DOM @ IE9 test: node
: type object, toString.call: [object Object], ""+node: [object HTMLDivElement], nodeType: 1: IE8: node : type object, toString.call: [object Object], ""+node: , nodeType: 1: node : type object, toString.call: [object Object], ""+node: [object], nodeType: 1: */ 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 ? ' <' + node.tagName // + (node.id ? '#' + node.id : '') + '>' : '') // + ': 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(/ 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; } })(); /** * 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('

使用注意事項

注意事項
注意事項 正文
*/ // 確保置中 function doAlertResize() { if (typeof doAlertDivName != 'string' || !doAlertDivName || !(o = document.getElementById(doAlertDivName))) return; o.style.position = 'absolute', o.style.display = 'block', o.style.width = '70%'; // 因為'%'是以整體長寬為主,故不適用。 if (false) { var t = Math.round(50 * (1 - o.offsetHeight / document.body.clientHeight)); if (t < 0) o.style.width = '99%', o.style.top = '0'; else o.style.top = t + '%'; t = Math .round(50 * (1 - o.offsetWidth / document.body.clientWidth)); o.style.left = t < 0 ? '0' : t + '%'; } if (false) alert(o.style.offsetHeight + ',' + window.offsetHeight + ',' + window.innerHeight + ',' + window.outerHeight); if (typeof window.innerHeight == 'undefined') window.innerHeight = document.body.clientHeight; if (typeof window.innerWidth == 'undefined') window.innerWidth = document.body.clientWidth; var t = (window.innerHeight - o.offsetHeight) / 2; if (t < 0) o.style.width = o.style.height = '99%', o.style.top = 0; else o.style.top = t + 'px'; t = (window.innerWidth - o.offsetWidth) / 2; // 不用marginTop與marginLeft,因為這裡要放置div o.style.left = t < 0 ? 0 : t + 'px'; } // 初始化 // doAlertInit[generateCode.dLK]='set_cookie,doAlert'; // n:div name function doAlertInit(n) { // 防止重複執行 if (false && typeof doAlertDone != 'undefined' && doAlertDone) return; // doAlertInit()重設 if (!n) { // Gecko need this _.set_cookie(_.set_cookie.f.set_root); _.set_cookie('doAlert'); return; } var d = document.getElementById(n); if (d) { if (typeof doAlertDivName == 'undefined') doAlertDivName = n; doAlert(); } } // 出現警告 // doAlert[generateCode.dLK]='doAlertInit,doAlertResize,doAlertAccess,doAlertScroll,doAlertDivName,doAlertOldScrollLocation,get_cookie,get_window_status'; // n:name,m:mode=1:use alert(),icon div的文字內容 function doAlert(n, m, iconContent) { if (!n && typeof doAlertDivName == 'string' && doAlertDivName) n = doAlertDivName; var o = document.getElementById(n), oBg = document.getElementById(n + 'Bg'), oI = document.getElementById(n + 'I'); if (!document.body || !o || m && !alert(o.innerHTML)) { // alert()會return undefined return; } if (!oI) try { // 只對IE5.5之後有用 // document.body.insertBefore(); o.parentNode .insertBefore(oI = document.createElement('div'), o); oI.id = n + 'I'; oI.onclick = function() { doAlertInit(); doAlert(); }; oI.title = "注意事項"; oI.innerHTML = iconContent || '別忘了'; oI.doAlertScrollT = oI.doAlertScrollL = 0; } catch (e) { return; } if (!oBg) try { // 只對IE5.5之後有用 o.parentNode.insertBefore(oBg = document.createElement('div'), o); oBg.id = n + 'Bg'; } catch (e) { return; } if (false) if (!oI || !oBg) alert('No index or bg div!'); disableKM(2); doAlertResize(); window.Oonresize = window.onresize; window.onresize = doAlertResize; oI.style.display = 'none'; oI.style.position = 'absolute'; oI.style.right = '.1em'; oI.style.top = '.1em'; // offset*:唯讀 oBg.style.position = 'absolute'; oBg.style.left = -parseInt(document.body.leftMargin); oBg.style.top = -parseInt(document.body.topMargin); oBg.style.width = height = '110%'; oBg.style.display = 'inline'; if (o.filters) { // try{}catch(e){} o.filters.alpha.opacity = 85; } if (oBg.filters) try { oBg.filters.alpha.opacity = 30; } catch (e) { } else { // for Moz o.style.position = 'fixed'; oBg.style.position = 'fixed'; oBg.style.opacity = oBg.style['-moz-opacity'] = .3; oBg.style.left = oBg.style.top = 0; oBg.style.width = oBg.style.height = '100%'; } if (get_cookie('doAlert') == n) doAlertAccess(n); else { // 奇怪的是,直接執行scrollTo(0,0)沒啥用。 o = get_window_status(); doAlertOldScrollLocation = [ o.scrollLeft, o.scrollTop ]; setTimeout('scrollTo(0,0);', 0); } } // pass function doAlertAccess(n) { if (!n && typeof doAlertDivName == 'string' && doAlertDivName) n = doAlertDivName; var o = document.getElementById(n), oBg = document.getElementById(n + 'Bg'); if (oBg) oBg.style.display = 'none'; o.style.display = 'none'; disableKM(0); window.onresize = window.Oonresize || null; if (doAlertOldScrollLocation) scrollTo(doAlertOldScrollLocation); doAlertScroll(1); } // icon div的捲動:置於右上角 // doAlertScroll[generateCode.dLK]='get_window_status'; function doAlertScroll(m) { var oI; if (typeof doAlertDivName != 'string' || !doAlertDivName || !(oI = document.getElementById(doAlertDivName + 'I'))) return; if (typeof m != 'undefined') { oI.style.display = m ? 'block' : 'none'; oI.doAlertScrollL = oI.offsetWidth + (m || 0); if (oI.currentStyle) { // IE if (m = parseInt(oI.currentStyle.paddingTop)) oI.doAlertScrollT = m; m = parseInt(oI.currentStyle.paddingLeft); if (m = parseInt(oI.currentStyle.paddingRight)) oI.doAlertScrollL += m; } else { oI.style.position = 'fixed'; if (false) { // Moz...but useless if (m = oI.offsetTop) oI.doAlertScrollT = m; m = oI.offsetLeft; if (m = oI.offsetRight) oI.doAlertScrollL += m; } } } if (false) { 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); } m = get_window_status(); oI.style.left = // -document.body.leftMargin-document.body.rightMargin m.scrollLeft + m.windowW - oI.doAlertScrollL + 'px'; // 只有在padding用px時有效! oI.style.top = m.scrollTop - oI.doAlertScrollT + 'px'; } /** * Sets / adds class of specified element.
* TODO:
* 1. 一次處理多個 className。
* 2. 以字串處理可能較快。
* 3. 用 +/- 設定。
* 4. https://developer.mozilla.org/en/DOM/element.classList * * TODO: using element.classList * https://www.webhek.com/post/you-do-not-need-jquery.html * * @param element * HTML elements * @param class_name * class name || TODO: {class name 1: true, class name 2: false, * ...} * @param options * default: just add the specified className options.reset: reset * className (else just add) options.status: return {className1:, * className2:, ...} options.remove: remove className * @return * @see className of type DOMString, element.className - MDC * @_memberOf _module_ */ function set_class(element, class_name, options) { if (element && typeof element === 'string') element = document.getElementById(element); if (!_.is_ELEMENT_NODE(element)) return; if (!options) options = Object.create(null); var c; if (class_name && !library_namespace.is_Object(class_name) && !options.remove) { c = Array.isArray(class_name) ? class_name.join(' ') : class_name; c = c.trim(); if (options.reset) { element.className = c; } else if (!(' ' + element.className + ' ').includes(' ' + c + ' ')) { // add 時不 detect 多重 class 是為了速度。 element.className += ' ' + c; } if (!options.status) return; } if (false) library_namespace.debug('set_class: remove [' + class_name + '] from [' + o.className + ']'); c = element.className.split(/\s+/); var r = Object.create(null), i, changed = options.reset; // 設定原先的 className. TODO: 增進效率。 if (!changed) for (i in c) r[c[i]] = true; if (library_namespace.is_Object(class_name)) { // 僅更動 class_name 指涉的部分。 for (c in class_name) if (r[c] !== (i = !!class_name[c])) changed = true, r[c] = i; // 已處理過,忽略 options.remove,不再處理。 class_name = null; } if (options.remove && class_name) { if (!Array.isArray(class_name)) class_name = [ class_name ]; for (i in class_name) { c = class_name[i]; if (c in r) { // 有做變動. changed = true; delete r[c]; } } } if (changed) { c = []; for (i in r) if (r[i]) c.push(i); element.className = c.join(' ').trim(); if (false) library_namespace.debug('set_class: → [' + element.className + ']'); } return r; } _// JSDT:_module_ .set_class = set_class; function clear_class(element) { if (element && typeof element === 'string') element = document.getElementById(element); if (('className' in element) && _.is_ELEMENT_NODE(element)) element.className = ''; } _// JSDT:_module_ .clear_class = clear_class; // if class_name is RegExp, class_name should NOT has global flag. function has_class(element, class_name) { var n = element.className, i; // class_name = class_name.trim(); if (!n || !class_name) return; if (Array.isArray(class_name)) { for (i = n = 0; i < class_name.length; i++) if (has_class(element, class_name[i])) n++; return n; } if (class_name = has_class.pattern(class_name)) return class_name.test(n); return n == class_name; } has_class.pattern = function(class_name) { if (class_name) { if (!library_namespace.is_RegExp(class_name)) class_name = new RegExp('(?:^|\\s)' + class_name + '(?:$|\\s)'/* ,i */); return class_name; } }; _// JSDT:_module_ . /** * If HTML element has specified class * * @param {HTMLElement}element * HTML elements * @param {String} * class_name class_name_1[ class_name_2 ...] * @return {Boolean} */ has_class = has_class; function find_class(class_name, parent_node, tag_name, selector, options) { var list = [], pattern, i, // elements = library_namespace.get_tag_list(tag_name || '*', parent_node || window.document), // length = elements.length; if (length > 0) { if (typeof selector !== 'function') selector = false; if ((pattern = has_class.pattern(class_name)) || selector) { library_namespace.debug('length: ' + length + ', pattern: ' + pattern, 2); for (i = 0; i < length; i++) { library_namespace.debug('#' + i + ': ' + elements[i].className, 2); if ((!pattern || pattern.test(elements[i].className)) && (!selector || selector.call(elements[i]))) { list.push(elements[i]); } } } else { list = elements; } } return list; } _// JSDT:_module_ . /** * @param {String} * class_name class_name_1[ class_name_2 ...] * @param {HTMLElement}element * HTML elements * @param {HTMLElement} * parent_node parent node * @param {String} * tag_name tag name * @return {[HTMLElement]} nodes * @see document.getElementsByClassName in prototype.js, jquery('.class') * * document.querySelectorAll() http://www.w3.org/TR/selectors-api/ * http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/04/17/document-queryselector-in-ie8.aspx */ find_class = find_class; /** * 處理 popup 用。 對className的tag作popup處理。 window.onload="set_up_popup()"; 正文 */ // set_up_popup[generateCode.dLK]='sPop,has_class'; function set_up_popup(tag, classN, func) { if (!tag) // 'span' tag = 'b'; /** * http://enable.nat.gov.tw/document/4_2.jsp http://ccca.nctu.edu.tw/~hlb/tavi/ABBRorACRONYM 應該用abbr(abbreviation/abbrevitated form/簡稱) abbr包含acronym(頭文字/首字母縮寫,通常這個字的發音像一個字) 根據W3C的規範說,中日文的縮寫格式要套用的是abbr標籤。 XHTML2.0把acronym移掉了,只剩下abbr標籤。 http://www.sovavsiti.cz/css/abbr.html if(!!document.all)document.body.innerHTML=document.body.innerHTML.replace(/<\s*(\/?)\s*abbr([>\s])/gi,'<$1span$2'); */ var i, j, o = library_namespace.get_tag_list(tag), popup_window_type; set_up_popup.list = []; if (o.length) for (i = 0; i < o.length; i++) { if (classN && !has_class(o[i], classN) || func && func(o[i])) continue; // 測試是否有特定標籤 for (j = 0, popup_window_type = ''; j < sPopP.allTypes.length; j++) if (o[i][sPopP.allTypes[j]]) { popup_window_type = sPopP.allTypes[j]; break; } if (popup_window_type // 有的話設定 event。 && (popup_window_type = sPop(o[i], sPopF[popup_window_type] | sPopF.nopop))) { if (false) o[i].innerHTML += '[' + sPopP.types[popup_window_type] + ']<\/b>'; set_up_popup.list.push(o[i]); if (popup_window_type == sPopF.window) { if (!o[i].onclick) { o[i].popup_type = popup_window_type; o[i].onclick = function() { sPop(this, this.popup_type); }; o[i].style.cursor = 'pointer'; } } else if (popup_window_type == sPopF.popup) { if (!o[i].onmouseover) { // o[i].ruby = o[i].popup = ''; o[i].onmouseover = function() { sPop(this, this.popup_type); }; if (!o[i].onmouseout) o[i].onmouseout = function() { sPop(this, sPopF.clearPop); }; if (!o[i].onclick) { o[i].onclick = function() { this.onmouseout = null; sPop(this, popup_window_type); }; o[i].style.cursor = 'pointer'; } } else if (false) { alert(popup_window_type + '\n' + sPopF[popup_window_type] + '\n' + typeof o[i].onmouseover + '\n' + o[i].onmouseover); } } } } } _.set_up_popup = set_up_popup; /** * 注釋(reference) / show popup-window or ruby 2004/4/3 17:20 http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K742.aspx example: txt txt window.onload="set_up_popup()"; + txt,txt txt 在每個字旁邊加上[[w:ja:圏点]] [●]或[○] sPop('txt') popup txt(自動設成sPopF.popup) sPop('txt',sPopF.window) popup txt by window flag & type: sPopF.title/sPopF.auto (依字數)自動選取 sPopF.ruby 採用 sPopF.popup 採用popup window sPopF.window 將資料開在新視窗 sPopF.nopop just test, don't popup(for ruby) sPopF.repeat repeat ruby sPopF.clearPop clear popup window sPopF.force 若是不能使用此種表示方法,則放棄顯示。(for popup @ Mozilla) style class application(應用): sPopP.DclassName中所定之className為觸發事件時會設定的class 執行環境environment: JScript @ HTML include function: String.repeat() parseFunction() set_Object_value() TODO: submenu http://dynamicdrive.com/dynamicindex1/popupmenu.htm Tipped - The Javascript Tooltip Framework http://projects.nickstakenburg.com/tipped How to Create a Valid Non-Javascript Lightbox | Carsonified http://carsonified.com/blog/design/css/how-to-create-a-valid-non-javascript-lightbox/ move/resize/最小化: popup dialog http://deluxepopupwindow.com/html-popup-dialog-vista-graphite.html 獨佔 window, 訊息列, 多功能(HTML+Script)內容 http://vision-media.ca/resources/jquery/jquery-popup-plugin-review key (Esc) time limit */ // sPop properties object var sPopP, // flag sPopF = { title : 0, auto : 0, nopop : 8, repeat : 16, clearPop : 32, force : 64 }, // for error sPopError; // 初始值設定 & 設定flag function sPopInit() { if (/* global. */sPopP) { alert('sPopP 已被佔用!'); return; } sPopP = Object.create(null); // 預設style class name:(null:used last time),ruby,popup,window sPopP.DclassName = ',popupedTxt_ruby,popupedTxt,popupedTxt'.split(','); // 已登記的背景style,請在CSS中加入[sPopC]_[body class name] sPopP.bgS = 'bgb,bgn'; { var i = 0, t = sPopP.bgS.split(','); sPopP.bgS = Object.create(null); for (; i < t.length; i++) sPopP.bgS[t[i]] = i + 1; } // popup window style 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);"; // chars to repeat(for ruby) 著重號(‧) // https://ja.wikipedia.org/wiki/圏点 sPopP.RepeatC = '‧•◦.。ヽ﹅﹆○●◎◉☆★※*#▽▼△▲◆◇□■↓↑' // .turnU() ; // types:auto,這些attribute可被處理,且將被視為自動選取type。 sPopP.autoTypes = 'title,_sPop' // +',_'+sPopP.functionName ; // types,最多七種 // +div(參考showLinkPopup() @ link.js) sPopP.types = 'ruby,popup,window'; // 所有可用的types,可用來detect是否能為sPop()所接受。但Mozilla中無法使用title之外的attribute。 sPopP.allTypes = (sPopP.autoTypes + ',' + sPopP.types).split(','); // function name sPopP.functionName = ''; if (false) sPopP.functionName = library_namespace.parse_function().funcName; // popup window(for popup) if (library_namespace.is_WWW() && typeof window.createPopup != 'undefined') sPopP.window = window.createPopup(); { var i = 0, t = sPopP.types.split(','), T = ''; for (; i < t.length;) sPopF[t[i]] = ++i; if (false) sPopF['_' + sPopP.functionName] = 0; } // sPopP.types[index] = type name sPopP.types = ( // '_' + sPopP.functionName + ',' + sPopP.types).split(','); // 註解 sPopP.commentTitle = 'Comment'; sPopP.commentTitlePattern = sPopP.commentTitle + ' of %s'; // close message: 關閉視窗或popup sPopP.close_message = 'Close'; // bigger message: 放大 sPopP.bigger_message = 'Bigger'; // reset size message: 回復原大小 sPopP.reset_message = 'Reset size'; } sPopInit(); // 只有 IE 5, firefox 38 提供ruby,所以沒有的時候不宜加入旁點功能。IE, Chrome 旁點顯示正確,但 firefox // 字體過小,僅 2/3。 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby var has_ruby_tag = library_namespace.platform({ ie : 5, firefox : 38, chrome : 5, safari : 5 }); // TODO: 點選文字後在下方出現全橫幅的layer以展示訊息,再點選可隱藏。 // e.g., // https://www.twreporter.org/a/bookreview-i-generation-discrimination-micro-aggression // 主object(正文或主object,會從之取得正文與注釋)[, flag, text string or // object(注釋,會蓋過從主object取得之text), 使用的class name] // sPop[generateCode.dLK]='sPopP,sPopF,sPopInit,*sPopInit();'; function sPop(oPos, flag, oTxt, classN) { if (false) if (flag & sPopF.clearPop) { if (sPopP.window) sPopP.window.hide(); return; } // input value test & 修正 if (!oPos && !oTxt) return; var limitW = screen.width - 50, limitH = screen.height >> 1; if (!sPopP.width) sPopP.width = 250; if (sPopP.width > limitW) sPopP.width = limitW; if (!sPopP.height) sPopP.height = 100; if (sPopP.height > limitH) sPopP.height = limitH; // 初始值設定 if (!sPopP.functionName && (sPopP.functionName = library_namespace.parse_function())) sPopF[sPopP.types[0] = '_' + (sPopP.functionName = sPopP.functionName.funcName)] = 0; else sPopP.functionName = ''; var repopMark = 'repop', repop = oPos === repopMark, nopop = flag & sPopF.nopop, popup_window_type = flag & 7, useAttbTxt = false, // 轉成br用 brReg = /\r*\n/g, brT = '
\n'; if (repop) { if (!sPopP.popObj || typeof sPopP.popObj != 'object' || typeof sPopP.popObj.innerHTML != 'string' || !sPopP.popObj.innerHTML) return; // 重新 pop up 時不作其他判別處置 oPos = sPopP.popObj; popup_window_type = sPopF.popup; } else { // 處理 object if (typeof oPos == 'string' && oPos) if (oPos.length < 32 && document.getElementById(oPos)) { // 輸入object name時轉成object oPos = document.getElementById(oPos); } else if (!oTxt) { // 若只輸入oPos,將之當作注釋(oTxt)。 oTxt = oPos; if (false) oPos = typeof null == 'object' ? 0 : null; // 若是typeof null=='object',請設成false oPos = 0; } // 設定oTxt 1/4 if (typeof oTxt == 'object' && oTxt.innerHTML) oTxt = oTxt.innerHTML; else if (oTxt) { // 轉成string oTxt += ''; } // (自動)判別使用的type var useAutoTxt; if (popup_window_type == sPopF.auto) { // 設定oTxt 2/4 : 知道是自動判別後先設定 if (typeof oPos == 'object' && (!oTxt || oTxt == 0)) if (oPos[sPopP.types[0]]) oTxt = oPos[sPopP.types[0]], useAutoTxt = true; else if (oPos.title) { // 以的用法來說,這是最常經過的path oTxt = oPos.title; useAutoTxt = true; } // 假如沒有oTxt.gText(),改成oTxt.replace(/<[^>]*>/g,'')之即可。這是為了預防HTML的情形。 var popup_length = typeof oTxt == 'string' ? oTxt.length // :typeof oTxt=='object'&&oTxt.innerHTML?oTxt.innerHTML.length : 0; if (false) alert(popup_length + ',' + (popup_length * .7) + ',' + oPos.innerHTML.length); var inner_length = (typeof oPos.innerText == 'string' ? oPos.innerText : _.HTML_to_Unicode(oPos.innerHTML // .replace(/<[a-z][^<>]*>/g, '') )).length; if (typeof oPos == 'object' && (oPos.doneRuby || !oPos.innerHTML.match(/<\s*ruby/i) // auto-detect the type to use. && popup_length < 60 && popup_length < 3 * inner_length && popup_length * .7 - 9 < inner_length)) { // ruby的條件 popup_window_type = 'ruby'; } else if (sPopP.window && popup_length < 300) { popup_window_type = 'popup'; if (typeof oPos == 'object' && oPos.title === oTxt) oPos[sPopP.types[0]] = oTxt, oPos.title = ''; } else { popup_window_type = 'window'; } // 設定oTxt 3/4 & type if (typeof oPos == 'object' && (!oTxt || oTxt == 0)) if (oPos[popup_window_type]) oTxt = oPos[popup_window_type], useAutoTxt = true; popup_window_type = sPopF[popup_window_type]; } // 設定oTxt 4/4 if (!oTxt || oTxt == 0 && typeof oPos != 'object') { if ((oTxt = oPos[sPopP.types[popup_window_type]]) || (oTxt = oPos[sPopP.types[0]]) || (oTxt = oPos.title)) useAutoTxt = true; else return; } // 設定className與position // popup left,popup top初始值 sPopP.left = 0, sPopP.top = 20; if (!oPos || typeof oPos != 'object') { // popup 在滑鼠指標處 // see: add_listener() try { sPopP.left += event.offsetX, sPopP.top += event.offsetY; } catch (e) { } } else if (!oPos.className && sPopP.DclassName[popup_window_type]) { if (!classN && (classN = document.body.className) && !sPopP.bgS[classN]) classN = 0; oPos.className = sPopP.DclassName[popup_window_type] + (classN ? '_' + classN : ''); var w, s = oPos.style; if (!s.fontWeight && (w = oPos.parentNode) && (w = w.style.fontWeight)) { // 除非有明確設定font-weight,否則通常不會有效 s.fontWeight = w; } } } // 修正 if (popup_window_type == sPopF.popup && !sPopP.window && !(flag & sPopF.force)) // Mozilla中無法顯示popup popup_window_type = sPopF.window; if (false) alert(sPopP.types[popup_window_type] + ',' + (sPopP.window || flag & sPopF.force) + ',' + oTxt); // 處理pop if (popup_window_type == sPopF.ruby) { if (typeof oPos != 'object' || !oPos.innerHTML) // oPop非HTML element就return return; if (oPos.doneRuby) // 已經處理過就pass return popup_window_type; // 處理repeat if (flag & sPopF.repeat || sPopP.RepeatC.indexOf(oTxt) !== -1) { oPos.title = ''; oTxt = has_ruby_tag ? oTxt .repeat((typeof oPos.innerText == 'string' ? oPos.innerText : _.HTML_to_Unicode(oPos.innerHTML // .replace(/<[a-z][^<>]*>/g, '') )).length / oTxt.length) : ''; } try { // 標準可以沒 。 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby oPos.innerHTML = '' + oPos.innerHTML + '<\/rb>' // 半形與全形的括弧 + (oTxt ? window.navigator.userAgent.indexOf("Opera") >= 0 || /^[a-z\d\s_,.;"'\[\]{}+\-*\/]*$/i.test(oTxt) ? '(<\/rp>' + oTxt + '<\/rt>)' : '(<\/rp>' + oTxt + '<\/rt>)' : '<\/rp><\/rt>') + '<\/rp><\/ruby>'; } catch (e) { var n = e.number & 0xFFFF; if (n == 601 && (typeof sPopError == 'undefined' || sPopError != n)) alert('Error: ' + e.description + ' at\n' + oPos.outerHTML + '\n\n★也許是在這之前的tag出錯,例如有卻沒有<\/b>。'); sPopError = n; } oPos.doneRuby = true; } else if (popup_window_type == sPopF.popup) { if (nopop || !sPopP.window) return popup_window_type; if (!repop) { if (useAutoTxt) oTxt = oTxt.replace(brReg, brT); // 這是一種註解功能,在mouseout後,假定讀者繼續讀下去,所以就讓popup // object消失。想要多看一點的,會去按他,這時才讓popup object繼續存在。 sPopP.window.document.body.innerHTML = // oTxt= '
[' + sPopP.close_message + '<\/b>] [' + sPopP.bigger_message + '<\/b>] [' + sPopP.reset_message + '<\/b>]
' + oTxt.replace(/'/g, ''') + '<\/div>'; // object handling now(for popup:repop) sPopP.popObj = oPos || document.body; if (false) if (typeof oPos.onmouseout != 'undefined') oPos.onmouseout = function() { sPopP.window.hide(); }; } if (false) alert(sPopP.width + ',' + sPopP.height); if (flag & sPopF.clearPop) sPopP.window.hide(); else sPopP.window.show(sPopP.left, sPopP.top, sPopP.width, sPopP.height, oPos || document.body); } else if (popup_window_type == sPopF.window) { if (nopop) return popup_window_type; if (false) if (typeof netscape == 'object') // 創造無邊框視窗:titlebar=no dependent:ns only 全螢幕:channelmode // 带有收藏链接工具栏的窗口:directories // 网页对话框:'dialogWidth:400px;dialogHeight:300px;dialogLeft:200px;dialogTop:150px;center:yes;help:yes;resizable:yes;status:yes' netscape.security.PrivilegeManager .enablePrivilege("UniversalBrowserWrite"); /** * dialogHeight: iHeight 设置对话框窗口的高度。 dialogWidth: iWidth 设置对话框窗口的宽度。    dialogLeft: iXPos 设置对话框窗口相对于桌面左上角的left位置。 dialogTop: iYPos 设置对话框窗口相对于桌面左上角的top位置。 center: {yes | no | 1 | 0 } 指定是否将对话框在桌面上居中,默认值是“yes”。 help: {yes | no | 1 | 0 } 指定对话框窗口中是否显示上下文敏感的帮助图标。默认值是“yes”。    resizable: {yes | no | 1 | 0 } 指定是否对话框窗口大小可变。默认值是“no”。 status: {yes | no | 1 | 0 } 指定对话框窗口是否显示状态栏。对于非模式对话框窗口,默认值是“yes”;对于模式对话框窗口,默认值是 “no”。 window.showModalDialog(), window.showModelessDialog(): IE only. 不如用Ajax */ var w = 'titlebar=no,dependent,resizable=1,menubar=0,toolbar=0,location=0,scrollbars=1,width=550,height=400'// ,fullscreen ; try { // old IE w = window.open('', 'comment', w, false); } catch (e) { // Chrome/89.0.4389.9 w = window.open('', 'comment', w); } // head var t = sPopP.commentTitle, // document.title _t = oPos.innerHTML && oPos.innerHTML.length < 9 ? sPopP.commentTitlePattern .replace(/%s/, oPos.innerHTML) : t; if (false) if (typeof netscape == 'object') netscape.security.PrivilegeManager .disablePrivilege("UniversalBrowserWrite"); if (document.title) t += ' @ [' + document.title + ']', _t += ' @ ' + document.title; else if (false) t += ' @ [' + location.pathname + '<\/a>]'; w.document.open(); w.document .write( /** * '' + _t + '<\/title><script type="text/javascript">window.onblur=function(){window.close();};<\/script><\/head><body><b style="color:#11f;">' + t + ':<\/b>' </code> */ '<script type="text/javascript">window.onblur=function(){window.close();};<\/script><b style="color:#11f;">' + t + ':<\/b>' // "white-space:normal;width:500px;" :useless ** // 這邊會對<b title="..等造成影響! + (oPos.innerHTML ? '<div id="s" style="color:#488;background-color:#FF8;">\n' + oPos.innerHTML.replace(/\n/g, '<br />') .replace(/ /g, ' ') + '\n<\/div><hr />' : '') + '<div id="c" style="color:#404;background-color:#8FF;">\n' + oTxt.replace(/\n/g, '<br />') // 以不換行(pre)的方式顯示.patch .replace(/ /g, ' ') + '\n<\/div><hr />[ <b style="cursor:pointer;color:#40f;" onclick="javascript:opener.focus();self.close();">' + sPopP.close_message + '<\/b> ]' // + '</body></html>' ); w.document.close(); w.document.title = _t; w.focus(); // open出來的窗口即使close了,它的window對象還是存在的,要記得刪除引用 // http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html w = null; } else if (false) alert('type error: ' + popup_window_type + '!'); // 回傳決定的type return popup_window_type; } /** * <code> 開啟連結於 target ** 最好將openAtInit();設在onload JScript solution for attribute 'target' @ XHTML1.1 <a target="tag">之取代策略 way 1: ,captureE,openAtInit,"openAtInit();",openAt onload: + openAtInit() ,captureE,openAtInit,"openAtInit();",openAt target="tag" → onclick="return openAt('tag')" target="_blank" → onclick="return openAt()" target="_self" → onclick="return openAt(1)" way 2: ,openAt target="_blank" → onclick="return openAt(0,this.href)" target="_self" → onclick="return openAt(1,this.href)" http://tohoho.wakusei.ne.jp/js/event.htm TODO: http://hi.baidu.com/monyer/blog/item/56f1c88095fc96d79023d931.html a{text:expr/*XSS* /ession(target="_blank");} http://blog.fanstown.net/blogs/jerry/archive/2007/04/04/HTML_8476_rel_5E5C2760E68BE3890230_.aspx 原來這樣寫的代碼: <a href="document.html" target="_blank"> 打開一個新窗口</a> 現在要寫成這樣: <a href="document.html" rel="external">打開一個新窗口</a> 這是符合strict標準的方法。當然還必須配合一個javascript才有效。 ** 應該 binding a.onclick 或 a.keypress rel是relationship的英文縮寫.rel與rev具有互補的作用,rel指定了向前鏈接的關係,rev指定了反向鏈接的關係. </code> */ var captureE; // 初始化設定 // openAtInit[generateCode.dLK]='captureE'; function openAtInit() { if (typeof captureE != 'object' && (typeof Event == 'object' || typeof Event == 'function')) { // for moz // http://developer.mozilla.org/en/docs/DOM:element.addEventListener // http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event if (Event.mousedown) window.captureEvents(Event.mousedown); if (Event.keydown) window.captureEvents(Event.keydown); window.onmousedown = window.onkeydown = function(_event) { // alert('openAtInit: '+_event.target.tagName); captureE = _event; }; } for (var i, a = library_namespace.get_tag_list('a'); i < a.length; i++) if (a[i].onclick && !a[i].onkeypress && ('' + a[i].onclick).indexOf('openAt') != -1) a[i].onkeypress = a[i].onclick; } // open h(ref) in tag(et) // openAt[generateCode.dLK]='captureE,openAtInit'; function openAt(tag, h) { if (// typeof tag=='undefined'|| !tag) tag = '_blank'; else if (tag === 1) tag = '_self'; var t; if (!h && typeof event == 'object') h = event.srcElement.href; // 對Gecko等使用標準(?)Document Object Model的 // http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html if (!h && typeof captureE == 'object' && typeof captureE.target == 'object') { t = captureE.target; while (!(h = t.href) && (t = t.parentNode)) ; } if (false) alert(h + ',' + tag + '\n' + captureE.target.parentNode.tagName + ":" // +captureE.target.parentElement().tagName ); if (h) window.open(h, tag).focus(); return false; } /** * <code> display mark to valid document <div id="valid"> </div> window.onload="addValid()"; 搞定之後把自己網站提交到W3C Sites收錄。 http://www.w3csites.com/ for RSS: http://rss.scripting.com/?url=http%3A%2F%2Flyrics.meicho.com.tw%2Fgame%2Frss.xml http://feedvalidator.org/check.cgi?url=http%3A%2F%2Flyrics.meicho.com.tw%2Fgame%2Frss.xml </code> */ // object to insert valid, target window/frame function addValid(v, tf) { if (location.protocol == 'file:') return; if (!v) v = 'valid'; if (typeof v != 'object') v = document.getElementById(v); if (!v) return 1; if (v.innerHTML.replace(/ /g, '').replace(/\s+/g, '')) return 2; if (typeof tf === 'undefined') { // tf = dQuote(tf); // tf = tf ? ' target="' + tf + '"' : ''; tf = 'valid_window'; } var i = 0, t = '', d, addValidData = [ 'Valid XHTML 1.1! by W3C http://validator.w3.org/check?uri=referer http://www.w3.org/Icons/valid-xhtml11' // ,'Valid XML 1.0! by W3C ' // http://jigsaw.w3.org/css-validator/validator?uri=~ , 'Valid CSS! by W3C http://jigsaw.w3.org/css-validator/check/referer http://jigsaw.w3.org/css-validator/images/vcss', 'Validome Validation Services http://www.validome.org/referer http://www.validome.org/images/valid/set2/valid_xhtml_1_1.png', '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', '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', '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' // http://webxact.watchfire.com/ ]; for (; i < addValidData.length; i++) if (d = addValidData[i].split(' '), d[1]) t += ' <a title="' + d[0] + '" href="' + d[1].replace(/~/g, encodeURI(location.href)) + '" target="' + tf + '">' + (d[2] ? '<img style="display:inline;width:88px;" alt="' // IE不通 // '" onclick="return openAt(\''+tf+'\');"><img // style="display:inline;" alt="' + d[0] + '" src="' + d[2] + '" />' : d[0]) + '<\/a>'; // tf.focus() else alert('Validate data defined error!'); v.innerHTML = 'Validate this document:<br />' + t; v.style.display = 'block'; return t; } /** * <code> 延遲執行: 加強版的 setTimeout? id=delayRun(function[,ms=0]) id=delayRun([function,[args],this] [,ms=0]) </code> */ function delayRun(f, ms) { var _f = delayRun, i; if (!_f.fL) _f.fL = []; i = _f.fL.length; _f.fL.push(f); setTimeout('delayRun.run(' + i + ');', ms || 0); return i; } delayRun.clear = function(i) { // clearTimeout(): 為求簡單省略 delete this.fL[i]; }; delayRun.run = function(i) { var _t = this, f = _t.fL[i]; if (f) { if (typeof f == 'function') f(); else if (Array.isArray(f)) f[0].apply(f[2] || null, f[1]); else eval(f); delete _t.fL[i]; } }; var VBalert_flags = { ret : 0, // http://msdn.microsoft.com/library/en-us/script56/html/vsfctmsgbox.asp vbOK : 1, vbCancel : 2, vbAbort : 3, vbRetry : 4, vbIgnore : 5, vbYes : 6, vbNo : 7, vbOKOnly : 0, vbOKCancel : 1, vbAbortRetryIgnore : 2, vbYesNoCancel : 3, vbYesNo : 4, vbRetryCancel : 5, // Critical Message icon (x) vbCritical : 16, // Warning Query icon (?) vbQuestion : 32, // Warning Message icon (!) vbExclamation : 48, // Information Message icon(i) vbInformation : 64, vbDefaultButton1 : 0, vbDefaultButton2 : 256, vbDefaultButton3 : 512, vbDefaultButton4 : 768, vbApplicationModal : 0, vbSystemModal : 4096 }; /** * <code> MsgBox, InputBox Titlebars Prefixed with 'VBScript' http://support.microsoft.com/default.aspx?scid=kb;en-us;234742 http://asp.programmershelp.co.uk/vbscriptmsgbox.php http://17.webmasters.com/caspdoc/html/vbscript_msgbox_function.htm 請加入下面一段中介function <script type="text/vbscript"> Function VBalert_vbf() VBalert_flags.ret = MsgBox(VBalert_flags.prompt, VBalert_flags.buttons, VBalert_flags.title, VBalert_flags.helpfile, VBalert_flags.context) End Function </script> or use: window.execScript( sExpression, sLanguage ); </code> */ function VBalert(prompt, buttons, title, helpfile, context) { if (typeof prompt == 'undefined') return; VBalert_flags.prompt = prompt || '', VBalert_flags.buttons = buttons || 0, VBalert_flags.title = title || ''; // Not available on 16-bit platforms. // http://msdn.microsoft.com/library/en-us/script56/html/vsfctmsgbox.asp VBalert_flags.helpfile = helpfile || '', VBalert_flags.context = context || 0; try { VBScript: VBalert_vbf(); return VBalert_flags.ret; } catch (e) { // alert('VBalert error:' + e.message); alert(VBalert_flags.prompt); } } // initialization. // VBalert(); if (false) alert(VBalert('12', VBalert_flags.vbInformation + VBalert_flags.vbDefaultButton3)); // TODO: get_size(node = window) = Object.create(null); /** * <code> get window status 取得視窗可利用的size。現在還得用種方法,真是羞恥。 2005/1/13 20:0 get_window_status(event object) http://www.mozilla.org/docs/dom/domref/dom_window_ref.html http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/body.asp http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=16 http://www.webdevtips.com/webdevtips/faq/javascript/index.shtml http://www.quirksmode.org/viewport/compatibility.html http://cgi.din.or.jp/~hagi3/JavaScript/JSTips/Mozilla/eventhandle.htm ** untested !! </code> */ var event_Object; /** * 取得當前 window status * * @param node * HTML element or Event object * @returns {Object} status */ function get_window_status(node) { var t = get_window_status.scroll(), r = { scrollLeft : t[0], scrollTop : t[1] }; // 能scroll的範圍:不準,yet test The height of the total page (usually the body // element) // t:test, true:all but Explorer Mac, false:Explorer Mac, would also // work in Explorer 6 Strict, Mozilla and Safari var t = typeof document.body.scrollHeight != 'undefined' && typeof document.body.offsetHeight != 'undefined' && document.body.scrollHeight > document.body.offsetHeight; r.scrollW = t ? document.body.scrollWidth : typeof document.body.offsetWidth != 'undefined' ? document.body.offsetWidth : null; r.scrollH = t ? document.body.scrollHeight : typeof document.body.offsetHeight != 'undefined' ? document.body.offsetHeight : null; // window 大小 // 2009/3/23 1:15:29 var NewIE = navigator.appVersion.indexOf("MSIE") != -1 && parseInt(navigator.appVersion.split("MSIE")[1]) > 6; r.windowW = typeof window.innerWidth != 'undefined' ? window.innerWidth : /* typeof offsetWidth!='undefined'?offsetWidth: */!NewIE && typeof document.body.clientWidth != 'undefined' ? document.body.clientWidth : document.documentElement && !isNaN(document.documentElement.clientWidth) ? document.documentElement.clientWidth // +offsetLeft : null; r.windowH = typeof window.innerHeight != 'undefined' ? window.innerHeight : /* typeof offsetHeight!='undefined'?offsetHeight: */!NewIE && typeof document.body.clientHeight != 'undefined' ? document.body.clientHeight : document.documentElement && !isNaN(document.documentElement.clientHeight) ? document.documentElement.clientHeight // +offsetTop : null; var noEmu; if (!node) if (typeof window.event === 'object') node = window.event; else if (typeof e === 'object') node = e; else if (typeof event_Object === 'object') noEmu = true, node = event_Object; if (node) { // Safari: yet test var isSafari = /Safari/i.test(window.navigator.appName); // window相對於screen位置:不準, yet test r.windowX = node.clientX - ((isSafari) ? r.scrollLeft : 0); r.windowY = node.clientY - ((isSafari) ? r.scrollTop : 0); // mouse位置 // http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_event.asp // http://www.mozilla.org/docs/dom/domref/dom_event_ref.html r.mouseX = node.clientX + ((!isSafari) ? r.scrollLeft : 0); r.mouseY = node.clientY + ((!isSafari) ? r.scrollTop : 0); if (!noEmu) // 模擬event obj,因為event obj不能在event發生時之function執行完後再取得 event_Object = { 'clientX' : node.clientX, 'clientY' : node.clientY }; if (false) alert(r.scrollLeft + ',' + r.scrollTop + '\n' + o.clientX + ',' + o.clientY); } return r; } // IE7遵照標準,不用 document.body.scrollLeft 而用 // document.documentElement.scrollLeft // http://hkom.blog1.fc2.com/blog-entry-423.html // http://diaspar.jp/node/47 get_window_status.scroll = function(node) { var box_model, od = node && node.ownerDocument; try { // from jQuery var div = document.createElement('div'); div.style.width = div.style.paddingLeft = '1px'; document.body.appendChild(div); _.get_window_status.box_model = box_model = div.offsetWidth === 2; if (!node) od = div.ownerDocument; document.body.removeChild(div).style.display = 'none'; div = null; } catch (e) { // TODO: handle exception } // 到這邊,若是 od 未設定,則所有取值與 node 無關。 // 因為大多有 ownerDocument,所以預設編入。 // 新的 browser,od 與 dv 皆應有設定。 /** * <code> Firefox/3.6.6: ownerDocument: [object HTMLDocument], defaultView: [object Window], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0 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 Safari/533.16: ownerDocument: [object HTMLDocument], defaultView: [object DOMWindow], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: 0 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 MSIE 5.0 @ MSIE 9.0 test: ownerDocument: [object], defaultView: undefined, box_model: false, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined MSIE 7.0 @ MSIE 9.0 test: ownerDocument: [object], defaultView: undefined, box_model: true, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined MSIE 8.0: ownerDocument: [object HTMLDocument], defaultView: undefined, box_model: true, pageXOffset: undefined, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined MSIE 9.0 test: ownerDocument: [object HTMLDocument], defaultView: [object Window], box_model: true, pageXOffset: 0, body.scrollLeft: 0, documentElement.scrollLeft: 0, scrollX: undefined </code> */ // IE5-8: od: true, dv: false var doc = node && od || window.document, body = doc.body, dv = doc.defaultView, win = dv || doc.parentWindow; 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'); // ** 順序有關係! 但在未設置 box_model 前,body.scrollLeft 排在 // documentElement.scrollLeft 前面。現在已按照 jQuery 改過。 // TODO: do test // [scrollLeft, scrollTop, clientLeft, clientTop] return (get_window_status.scroll = !isNaN(win.pageXOffset) ? // 預設 box_model === true function(n) { // '|| window.document': for Range (see get_selection()) var d = n && n.ownerDocument || window.document, w = d.defaultView; d = d.documentElement; return [ w.pageXOffset, w.pageYOffset, d.clientLeft, d.clientTop ]; } : // IE7(6?)~8 box_model && !isNaN(doc.documentElement.scrollLeft) ? function(n) { var d = (n && n.ownerDocument || window.document).documentElement; return [ d.scrollLeft, d.scrollTop, d.clientLeft, d.clientTop ]; } : // IE5(6?) !isNaN(body.scrollLeft) ? function(n) { var b = (n && n.ownerDocument || window.document).body; return [ b.scrollLeft, b.scrollTop, b.clientLeft, b.clientTop ]; } : !isNaN(win.scrollX) ? // untested function() { var b = document.body; return [ window.scrollX, window.scrollY, b.clientLeft, b.clientTop ]; } : function() { return [ 0, 0, 0, 0 ]; })(node); }; _// JSDT:_module_ .get_window_status = get_window_status; function set_style(element, name, value) { if (element && typeof element === 'string') element = document.getElementById(element); if (typeof element.style !== 'object') { library_namespace.warn('The element has no .style property!'); return; } if (typeof name === 'object' && !value) { Object.assign(element.style, name); if (false) { var pair = name; for (name in pair) { value = pair[name]; set_style(element, name, value); } } return; } if (!(name in element.style)) { library_namespace.warn('There is no property [' + name + '] in the element!'); return; } element.style[name] = value; } _.set_style = set_style; /** * get current computed style property of specified HTML element. TODO: 整合 * get_node_offset, _.set_style * * TODO: using getComputedStyle(element)[name] * * @param element * HTML element * @param name * W3C style property name, rule_name (e.g., no * '-webkit-background-clip') * @return * @see http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug, * http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K983.aspx, * curCSS @ jQuery, http://api.jquery.com/category/css/, <a * href="http://www.quirksmode.org/dom/getstyles.html" * accessdate="2010/4/1 15:44">JavaScript - Get Styles</a>, <a * href="http://www.javaeye.com/topic/140784?page=2" * accessdate="2010/4/1 15:41">style.display取值不对,难道是浏览器bug?讨论第2页: - * JavaScript - web - JavaEye论坛</a> 大體上,currentStyle 相當於 * getComputedStyle,而 runtimeStyle 相當於 * getOverrideStyle。但是它們還是有很重要的區別。那就是,IE的CSS計算步驟其實是不合標準的。 * document.defaultView 在 mozilla 中是指向 window obj 的,但是很有可能在其他 broswer * 中就不指向 window obj.. 因為 w3c 中沒有強行規定 document.defaultView 一定是一個global * obj. * * 返回頁內樣式表定義的類,那麼可以使用DOM樣式表對象來訪問: var oCssRulers = * document.styleSheets[0].cssRulers || document.styleSheets[0].rulers; * (前者是DOM方法,後者是IE私有方法) alert(oCssRulers[0].style.display); * @since 2010/4/2 00:14:09 refactoring 重構 * @_memberOf _module_ */ function get_style(element, name, options) { // CeL.get_style(element, 'display') // window.getComputedStyle(element).display if (element && typeof element === 'string') element = document.getElementById(element); options = library_namespace.setup_options(options); // TODO: options.no_computed // opacity if (!element || !name) return; var value, style_interface, e; name = name.toLowerCase(); // IE: element.style.styleFloat, firefox, chorme, safari: // element.style.cssFloat if (false) if (name === 'float') name = 'cssFloat' in element.style ? 'cssFloat' : 'styleFloat'; if (style_interface = // window.getComputedStyle document.defaultView) { try { if ((value = element.ownerDocument) && (value = value.defaultView)) style_interface = value; else // library_namespace.node_description() @ // application.debug.log library_namespace .debug('Cannot get .ownerDocument.defaultView of ' + (library_namespace.node_description ? library_namespace .node_description(element) : 'node') + ' !'); if (false) if (/[A-Z]/.test(name)) name = name.replace(/([A-Z])/g, '-$1').toLowerCase(); // width 之類可能 === "auto"!! value = style_interface.getComputedStyle(element, null) // [name] .getPropertyValue(name); // from curCSS @ jQuery: return a number for opacity if (name === 'opacity' && value === '') value = 1; } catch (e) { library_namespace.warn('get_style(name: ' + name + ') error!'); library_namespace.error(e); } } else if (style_interface = element.currentStyle) { // IE 5-8 // IE: \w+\W\w+ (e.g., margin-bottom), firefox, chorme, safari: // \w+-\w+ // IE8 中 width 之類可能 === "auto"!! value = style_interface[name === 'float' ? 'styleFloat' : name .replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); })]; // Dean Edwards(Base2類庫的作者)的hack // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 } else if ((style_interface = element.style) && (name in style_interface)) { value = style_interface[name]; } else { // we should directly get it from element itself if (!(value = element['offset' + name.charAt(0).toUpperCase() + name.slice(1).toLowerCase()])) value = ''; } // 處理 px, pt, em, ... library_namespace.debug((library_namespace.node_description // ? library_namespace.node_description(element) : 'node') // + '.style[' + name + '] = [' + value + ']' // + (style_interface === document.defaultView // ? ' (use W3C .getComputedStyle)' // : style_interface === element.currentStyle // ? ' (use IE .currentStyle)' : '')); if (options.numeral && typeof value === 'string') { var matched = value.match(/^(\d+(\.\d+)?)px$/); if (matched) { value = +matched[1]; } } return value; } _// JSDT:_module_ .get_style = get_style; // not yet tested. function get_style_sheets(filter, limit) { var filter_name, filter_item, filter_item_is_RegExp, i, sheet_property, length, tmp_style_sheets, // tag_list_default(document.styleSheets) style_sheets = document.styleSheets; if (!style_sheets || !style_sheets.length) return []; if (library_namespace.is_Object(filter)) { for (filter_name in filter) { filter_item = filter[filter_name]; filter_item_is_RegExp = library_namespace .is_RegExp(filter_item); tmp_style_sheets = []; for (i = 0, length = style_sheets.length; i < length && (!limit || tmp_style_sheets.length < limit); i++) { sheet_property = style_sheets[i][filter_name] || ''; if (filter_item_is_RegExp ? filter_item .test(sheet_property) : sheet_property .indexOf(filter_item) !== -1) tmp_style_sheets.push(style_sheets[i]); } style_sheets = tmp_style_sheets; } } return style_sheets; } ; _// JSDT:_module_ .get_style_sheets = get_style_sheets; _// JSDT:_module_ .get_style_sheet = function(filter) { return get_style_sheets(filter, 1)[0]; }; /** * get the actual position [left,top,width,height] of an HTML node object * * @param node * HTML node object * @return * @_memberOf _module_ * @deprecated use get_style(), jQuery.offset(), jQuery.position() * @see http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug, * http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K983.aspx, * http://msdn.microsoft.com/library/en-us/dndude/html/dude04032000.asp, * http://www.mail-archive.com/mochikit@googlegroups.com/msg00584.html, * http://hartshorne.ca/2006/01/20/javascript_positioning/, * http://www.jb51.net/article/18340.htm, * http://blog.csdn.net/wangjj_016/archive/2010/04/09/5467507.aspx */ function get_node_offset(node) { if (!(node = get_element(node))) return {}; var _s = _.get_node_offset, offset = 'offsetWidth' in node ? { width : node.offsetWidth, height : node.offsetHeight } : {}; if (node.getBoundingClientRect) { // also see: getClientRects() var s = get_window_status.scroll(node), box = node .getBoundingClientRect(); offset = { left : box.left + s[0] - s[2], top : box.top + s[1] - s[3], width : box.right - box.left, height : box.bottom - box.top }; } else if (_.is_HTML_element(node)) { if (false) alert(node.id + ':' + node.offsetLeft + ',' + node.offsetTop + ';' + node.offsetWidth + ',' + node.offsetHeight); var l = 0, t = 0, p; // var n, countH = window.navigator.userAgent.indexOf("MSIE") >= 0, // add = 1, outsideBLOCK = 1; if (false) if (typeof node.offsetWidth !== 'undefined') { var _w = node.offsetWidth, _h = node.offsetHeight; // var _o = window.getComputedStyle ? // document.defaultView.getComputedStyle(node, null) : null; if (false) { // http://www.quirksmode.org/dom/getstyles.html if (_o) { // moz未包含margin+border+padding // 這些值可能會有'em'等等的出現,不一定都是px! if (false) alert(_o .getPropertyValue('border-left-width') + ',' + _o .getPropertyValue('border-right-width')), _w += parseInt(_o .getPropertyValue('border-left-width')) + parseInt(_o .getPropertyValue('border-right-width')), _h += parseInt(_o .getPropertyValue('border-top-width')) + parseInt(_o .getPropertyValue('border-bottom-width')); } else if (_o = node.currentStyle) { // IE // IE的offset已經包含margin+border+padding的部份??另,這些值可能會有'em'等等的出現,不一定都是px。 _w += parseInt(_o['borderLeftWidth']) + parseInt(_o['borderRightWidth']); _h += parseInt(_o['borderTopWidth']) + parseInt(_o['borderBottomWidt']); } } r.width = _w; r.height = _h; } // 下面這段依瀏覽器而有不同 (-_-)!! // position:absolute // for debug // var tt=''; // 2006/2/14: 經由 offset 一個個溯源 var _o = node; while (_o && !isNaN(_o.offsetLeft)) { // IE在用style:class時會出現誤差。 if (false) { n = _o.tagName; if (false) if (!/^T(ABLE|BODY|R)$/.test(n = _o.tagName) && (countH || !/^H\d$/.test(n))) l += _o.offsetLeft, t += _o.offsetTop; if (n == 'DIV') add = outsideBLOCK; else if (n == 'TD' || countH && /^H\d$/.test(n)) add = 1; outsideBLOCK = // _o.style.display n == 'TABLE' || n == 'DIV'; tt += (add ? '' : '#') + n + (_o.style.display ? '(' + _o.style.display + ')' : '') + ':' + _o.offsetLeft + ',' + _o.offsetTop + (outsideBLOCK ? ', outside BLOCK' : '') + '\n'; if (add) add = 0, l += _o.offsetLeft, t += _o.offsetTop; } l += _o.offsetLeft || 0, t += _o.offsetTop || 0; _o = // .parentNode _o.offsetParent; } // 有些會用到overflow,影響位置。 2008/5/31 0:10:7 _o = node; while ((_o = _o.parentNode) && _o.tagName.toLowerCase() != 'body') l -= _o.scrollLeft || 0, t -= _o.scrollTop || 0; // need to enable definition of tt above if (false) alert('l ' + l + ',t ' + t + ',w ' + r.w + ',h ' + r.h + (typeof tt == 'string' ? '\n' + tt : '')); offset.left = l; offset.top = t; } return offset; } _// JSDT:_module_ .get_node_offset = get_node_offset; /** * <code> // get the [left,top,width,height] of obj function get_node_offset2(obj){ if(typeof obj=='string'){var o=document.getElementById(obj);if(o)obj=o;} // 若loc為id if(typeof obj=='object'&&typeof obj.offsetLeft!='undefined'){ // 若obj為Document Object //alert(obj.id+':'+obj.offsetLeft+','+obj.offsetTop+';'+obj.offsetWidth+','+obj.offsetHeight); var l=obj.offsetLeft,t=obj.offsetTop,n,add,outsideBLOCK,countH=window.navigator.userAgent.indexOf("MSIE")>=0,r=[]; 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; // 下面這段依瀏覽器而有不同 (-_-)!! // position:absolute //var tt=obj.tagName+':'+obj.offsetLeft+','+obj.offsetTop+'\n'; // for debug while(isNaN((obj=obj.parentNode).offsetLeft)){ // IE在用style:class時會出現誤差。 n=obj.tagName; //if( !/^T(ABLE|BODY|R)$/.test(n=obj.tagName) && (countH||!/^H\d$/.test(n)) )l+=obj.offsetLeft,t+=obj.offsetTop; if(n=='DIV')add=outsideBLOCK; else if(n=='TD' || countH&&/^H\d$/.test(n))add=1; outsideBLOCK= n=='TABLE'||n=='DIV'; // obj.style.display //tt+=(add?'':'#')+n+(obj.style.display?'('+obj.style.display+')':'')+':'+obj.offsetLeft+','+obj.offsetTop+(outsideBLOCK?', outside BLOCK':'')+'\n'; if(add)add=0,l+=obj.offsetLeft,t+=obj.offsetTop; } //alert('l'+l+',t'+t+',w'+w+',h'+h+'\n'+tt); // need to enable definition of tt above r[0]=r.left=r.l=r.L=l,r[1]=r.top=r.t=r.T=t; return r; } } </code> */ /** * <code> locate a object(obj/div, dialogue box, popup dialog) on where we want followed window location 2005/1/12 19:-13 21:22 此函數會盡量不使obj超出window範圍的大小,除非設定了noResize/noMove或發生錯誤。若moveable+resizable(default),會嘗試先move再resize。 obj: node or id. node 需要已經插入在 document.body 中。 loc: [left,top]/[left,top,width,height]/reference obj or id/0||'mouse':by mouse loc 若left,top設定成%或是0.-,會當作相對於螢幕的比例。 margin: 0/num=[num,num]/[offset x,offset y] 在可能的情況下(不會造成超出window範圍)與loc之間空出的距離(所作的位移)。假如未輸入則自動設定。 flag: locate_node_flag.~ !表示未實作 下面幾項為預設模式 auto[Locate] 自動調整位置(default),若設定abs/rel則不會自動調整。 resizable 可調整obj大小(default) ↔ noResize moveable 可移動obj(default) ↔ noMove 下面幾項為模式選擇,擇一。 auto[Locate] 自動判定並調整位置(default),若設定abs/rel則不會自動調整。 abs[olute] 這裡的loc為絕對location。假如有提供margin,則會嘗試定位於loc+margin處。 rel[ative] 這裡的loc為相對於window左上角的location。假如有提供margin,則會嘗試定位於loc+margin處。 asDialog,dialog 預設是普通obj,但當設定為此項(dialog)時,loc會被當成reference obj。 作為某obj(loc)之附屬obj(對話框/說明等),會避開主obj(reference obj)之顯示範圍。 假如提供的loc並非obj,則會假設主obj是個從loc開始,長寬為margin的object。 dialogDown,dialogUp,dialogRight,dialogLeft 預設是擺在下面,此flag可改成上面或其他不同方位。 擇一 resizable 可調整obj大小(default) ↔ noResize noResize 不可調整obj大小,若可移動會將整個obj移到能看清的邊界。 擇一 moveable 可移動obj(default) ↔ noMove noMove 不可移動obj,若可調整大小會將整個obj縮到能看清的大小。 下面幾項可任喜好選購(笑) keepDisplay 是否維持顯示之display mode。沒有時則顯示之。 create 假如不存在此obj就造出來。預設若無法取得此obj則會直接return ! !假如沒足夠空間則不顯示,或是僅顯示警告。 * 假如在事件中設定'event_Object=event'可掌握mouse event TODO: locate_nodeClip=[l,t,w,h]: resizable時將obj限制在這個範圍內 to top: var locate_node_flag; library_namespace.set_Object_value('locate_node_flag','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 </code> */ var locate_node_flag = { 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 }; // locate_node[generateCode.dLK]='event_Object,locate_node_flag,get_window_status,locate_node'; function locate_node(obj, loc, margin, flag) { // 前置處理 // setup obj if (!flag) flag = locate_node_flag.auto; if (!obj) return; if (typeof obj == 'string') { var id = obj; if (!(obj = document.getElementById(id)) && (flag & locate_node_flag.create)) document.body.appendChild(obj = document.createElement('div')), obj.id = id; } // 在 dialog 時之預設位移 var dMargin = { 'X' : 2, 'Y' : 2 }, Display = flag & locate_node_flag.keepDisplay ? obj.style.display : 'block', Visibility = flag & locate_node_flag.keepDisplay ? obj.style.visibility : 'visible', win, dialog = (flag & locate_node_flag.modeFlag) == locate_node_flag.dialog ? flag & locate_node_flag.dialogFlag : 0, turnPercent = function(p, v) { if (typeof p == 'string') { var t = parseFloat(p.match(/([\d.]+)/)); p = t ? t < 2 ? t * v : t < 200 ? t * v / 100 : t : 0; } else if ( // typeof p1='undefined'&& isNaN(p)) p = 0; return p; }, handle_percent = function(o, t) { // t: 0:loc, 1:margin // 是否重新指定 var d = 0; if (typeof o == 'string') o = o.split(','), d = 1; if (!dialog && typeof o == 'object') { // 取百分比% if (typeof o[t ? 'left' : 'X'] == 'undefined' && typeof o[0] != 'undefined') d = 1, o = t ? { 'X' : o[0], 'Y' : o[1] } : { 'left' : o[0], 'top' : o[1], // 假如o[2]未定義,width也會未定義(但有index) 'width' : o[2], 'height' : o[3] }; if (t) o.X = turnPercent(o.X, win.windowW), o.Y = turnPercent(o.Y, win.windowH); else { o.left = turnPercent(o.left, win.windowW), o.top = turnPercent(o.top, win.windowH); if (typeof o.width == 'undefined') { delete o.width; delete o.height; } else o.width = turnPercent(o.width, win.windowW), o.height = turnPercent(o.height, win.windowH); } } if (d) if (t) margin = o; else loc = o; }, makeFit = function(l, t, r, b, hc) { // test if out of range & // 將box調整在range[left,top,right,bottom]內:先move,再resize if (boxL < l) boxL = l; if (boxT < t) boxT = t; var d = r - obj.offsetWidth; if (boxL > d) if (l > d) boxW = r - (boxL = l); else boxL = d; d = b - obj.offsetHeight; if (boxT > d) if (t > d) boxH = b - (boxT = t); else boxT = d; else if (hc && (boxT = hc - obj.offsetHeight / 2) < t) boxT = t; }; obj.style.overflow = obj.style.visibility = 'hidden'; if (obj.style.width) obj.style.width = ''; if (obj.style.height) // 重設obj。 obj.style.height = ''; // 得設定obj之display,因為不這樣不能定offset。但可不顯現出來…只是好像沒啥效果。 obj.style.display = 'block'; if (false) if (dialog != locate_node_flag.dialogDown && dialog != locate_node_flag.dialogUp) dialog = 0; // setup loc#1: handle dialog if (typeof loc == 'string') { // 若loc為id var o = document.getElementById(loc); if (o) loc = o; } if (typeof loc == 'object' && typeof loc.offsetLeft != 'undefined') { // 若loc為Document Object if (false) { if (false) alert(loc.id + ':' + loc.offsetLeft + ',' + loc.offsetTop + ';' + loc.offsetWidth + ',' + loc.offsetHeight); var l = loc.offsetLeft, t = loc.offsetTop, w, h, n, add, outsideBLOCK, // 真妙...moz表示在<H\d>中的obj時不把H\d當作parent算進去 countH = window.navigator.userAgent.indexOf("MSIE") >= 0; if (typeof loc.offsetWidth != 'undefined') { // loc.offsetWidth可能未定義? w = loc.offsetWidth; h = loc.offsetHeight; } // for debug // var tt = loc.tagName + ':' + loc.offsetLeft + ',' + // loc.offsetTop + '\n'; // 下面這段依瀏覽器而有不同 (-_-)!! while (isNaN((loc = loc.parentNode).offsetLeft)) { // IE在用style:class時會出現誤差。 n = loc.tagName; if (false) if (!/^T(ABLE|BODY|R)$/.test(n = loc.tagName) && (countH || !/^H\d$/.test(n))) l += loc.offsetLeft, t += loc.offsetTop; if (n == 'DIV') add = outsideBLOCK; else if (n == 'TD' || countH && /^H\d$/.test(n)) add = 1; outsideBLOCK = n == 'TABLE' || n == 'DIV'; // loc.style.display if (false) { tt += (add ? '' : '#') + n + (loc.style.display ? '(' + loc.style.display + ')' : '') + ':' + loc.offsetLeft + ',' + loc.offsetTop + (outsideBLOCK ? ', outside BLOCK' : '') + '\n'; } if (add) add = 0, l += loc.offsetLeft, t += loc.offsetTop; } if (false) { // need to enable definition of tt above alert(l + ',' + t + '\n' + tt); } loc = { 'left' : l, 'top' : t, 'width' : w, 'height' : h }; } loc = get_node_offset(loc); if ((flag & locate_node_flag.modeFlag) == locate_node_flag.auto) flag += locate_node_flag.dialog - locate_node_flag.auto, dialog = locate_node_flag.dialog; } // setup margin win = get_window_status(); if (!margin) margin = // dialog ? dMargin : {'X' : 0, 'Y' : 0}; dMargin; else handle_percent(margin, 1); // setup loc#2: handle abs/rel if (!loc || loc == 'mouse') loc = { left : win.mouseX || 0, top : win.mouseY || 0 }; else { if ((flag & locate_node_flag.modeFlag) == locate_node_flag.auto && typeof loc == 'string' && /[%.]/.test(loc)) flag += locate_node_flag.rel - locate_node_flag.auto; handle_percent(loc); } if (false) alert(loc.left + ',' + loc.top + ';' + margin.X + ',' + margin.Y); if ((flag & locate_node_flag.modeFlag) == locate_node_flag.auto) // 到這裡還沒決定就很奇怪了 flag += locate_node_flag[loc.width && loc.height && loc.top < win.windowH && loc.left < win.windowW ? (dialog = locate_node_flag.dialog) && 'dialog' : 'abs'] - locate_node_flag.auto; // 調整與判別 if (false) { alert(loc.left + ',' + loc.top + ';' + margin.X + ',' + margin.Y); alert(loc.left + margin.X + ',' + (loc.top + margin.Y)); alert('dialog:' + dialog); } if ((flag & locate_node_flag.modeFlag) == locate_node_flag.rel) { // 改成絕對座標。此後僅存abs/dialog flag += locate_node_flag.abs - locate_node_flag.rel // - (flag & locate_node_flag.modeFlag) ; loc.left += win.scrollLeft; loc.top += win.scrollTop; } // 最後要設定的值 var resizable = !(flag & locate_node_flag.noResize), boxL = loc.left, boxT = loc.top, boxW = -1, boxH = -1; if (flag & locate_node_flag.noMove) if (resizable) makeFit((boxL += margin.X) - margin.X, (boxT += margin.Y) - margin.Y, win.scrollLeft + win.windowW, win.scrollTop + win.windowH); else { if (margin.X < 0 || boxL + margin.X >= win.scrollLeft && boxL + margin.X + obj.offsetWidth < win.scrollLeft + win.windowW) boxL += margin.X; if (margin.Y < 0 || boxT + margin.Y >= win.scrollTop && boxT + margin.Y + obj.offsetHeight < win.scrollTop + win.windowH) boxT += margin.Y; } else if (!dialog) // abs boxL += margin.X, boxT += margin.Y, makeFit(win.scrollLeft, win.scrollTop, win.scrollLeft + win.windowW, win.scrollTop + win.windowH); else { // 自動調整位置 if (dialog) { if (!loc.width) loc.width = 0; if (!loc.height) loc.height = 0; } else // abs時, 相當於dialog在(0,0)大小(0,0) loc = { 'left' : win.scrollLeft, 'top' : win.scrollTop, 'width' : 0, 'height' : 0 }; if (!obj.innerHTML) // 起碼先設定個大小以安排位置 obj.innerHTML = ' '; var lA = win.scrollTop + win.windowH - loc.top - loc.height, lB = loc.top - win.scrollTop, lC = win.scrollLeft + win.windowW - loc.left - loc.width, lD = loc.left - win.scrollLeft, // args for makeFit() m1 = win.scrollLeft, m2 = win.scrollTop, m3 = win.scrollLeft + win.windowW, m4 = win.scrollTop + win.windowH // move kind set use locate_node_flag.dialog~ flag , movekind; if (false) alert(lA + ',' + lB + ',' + lC + ',' + lD + '\n' + obj.offsetWidth + ',' + obj.offsetHeight); /** * <code> +---------------------+ | ^ | | | lB | <--screen (active frame) | | | |<---->#####<-------->| ###:reference obj | lD | lC | | | | | | lA | | | | +---------------------+ </code> */ // 決定 mode if (dialog && (flag & locate_node_flag.dialogForce)) movekind = dialog; else { if (obj.offsetWidth < win.windowW && (dialog != locate_node_flag.dialogRight && dialog != locate_node_flag.dialogLeft || obj.offsetHeight >= win.windowH)) if (obj.offsetHeight < lA && (dialog != locate_node_flag.dialogUp || obj.offsetHeight >= lB)) movekind = locate_node_flag.dialogDown; else if (obj.offsetHeight < lB) movekind = locate_node_flag.dialogUp; if (!movekind && obj.offsetHeight < win.windowH) if (obj.offsetWidth < lC && (dialog != locate_node_flag.dialogLeft || obj.offsetWidth >= lD)) movekind = locate_node_flag.dialogRight; else if (obj.offsetWidth < lD) movekind = locate_node_flag.dialogLeft; if (!movekind) movekind = // 以較大、可視的為準 dialog != locate_node_flag.dialogRight && dialog != locate_node_flag.dialogLeft ? // 沒考慮假如lA<5時... lA < lB && resizable ? locate_node_flag.dialogUp : locate_node_flag.dialogDown : // lC < lD && resizable ? locate_node_flag.dialogLeft : locate_node_flag.dialogRight; } // alert(movekind); // 決定location if (movekind == locate_node_flag.dialogDown) { m2 = loc.top + loc.height; boxT += loc.height; if (!m1) m1 = loc.left; } else if (movekind == locate_node_flag.dialogUp) { m4 = loc.top; boxT -= obj.offsetHeight; margin.Y = -margin.Y; if (!m1) m1 = loc.left; } else if (movekind == locate_node_flag.dialogRight) m1 = loc.left + loc.width, boxL += loc.width; else m3 = loc.left, boxL -= obj.offsetWidth, margin.X = -margin.X; // else if(movekind==locate_node_flag.dialogLeft) // 加上偏移 boxL += margin.X, boxT += margin.Y; if (!resizable) { if (boxL < m1 && margin.X < 0 || boxL + obj.offsetWidth > m3 && margin.X > 0) boxL -= margin.X; if (boxT < m2 && margin.Y < 0 || boxT + obj.offsetHeight > m4 && margin.Y > 0) boxT -= margin.Y; // 確保不會撞到 m3 += obj.offsetWidth, m4 += obj.offsetHeight; } // 奇怪的是,alert(obj.offsetWidth)後obj.offsetWidth就變成0了。可能因為這值需要出函數之後再改。 if (false) alert(resizable + '\n' + m1 + ',' + m2 + ',' + m3 + ',' + m4 + ',' + movekind + '\n' + obj.offsetWidth + ',' + obj.offsetHeight); makeFit(m1, m2, m3, m4, movekind == locate_node_flag.dialogRight || movekind == locate_node_flag.dialogLeft ? loc.top : 0); } // 需要設在如 auto_TOC() layer 之上。 obj.style.zIndex = 100; // 設定位置 if (false) alert(boxL + ',' + boxT + ',' + boxW + ',' + boxH + ',' + Display); obj.style.position = 'absolute'; obj.style.left = boxL + 'px'; obj.style.top = boxT + 'px'; if (boxW >= 0 || boxH >= 0) { obj.style.overflow = 'auto'; if (false) alert(obj.style.width + ',' + obj.style.height + '\n' + typeof obj.style.width + '\n→w,h:' + boxW + ',' + boxH); if (boxW >= 0) obj.style.width = boxW + 'px'; if (boxH >= 0) obj.style.height = boxH + 'px'; } obj.style.display = Display; obj.style.visibility = Visibility; if (false) alert(obj.style.width + ',' + obj.style.height + '\n' + obj.offsetWidth + ',' + obj.offsetHeight); return obj; } _.locate_node = locate_node; /** {private} */ function limit_input_maxlength() { if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength); } /** {private} */ function limit_input_maxlength_onkeydown() { return this.value.length <= this.maxLength; } /** {private} */ function check_input_pattern_onkeydown() { if (false) if (this.value > this.getAttribute('max')) this.value = this.getAttribute('max'); return this.validator.test(this.value); } /** {private} */ function check_input_onkeydown(event) { // console.log([ this.value, this.maxLength, this.validator ]); // console.log(event); // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/charCode // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode if (event.ctrlKey || event.altKey || [ // backspace 8, // tab 9, // enter 13, // delete 46, // End 35, // Home 36, // arrow keys<^>v 37, 38, 39, 40 ].includes(event.which)) { return true; } // https://stackoverflow.com/questions/8354975/how-can-i-limit-possible-inputs-in-a-html5-number-element if (window.getSelection && window.getSelection().toString() // when select text and input || document.selection && document.selection.type !== 'Control' && document.selection.createRange().text) { return true; } return (!(this.maxLength >= 0) || this.value.length < this.maxLength) && (!this.validator || this.validator.test(this.value + event.key)); } _.adapt_input_validation = function adapt_input_validation() { for_nodes(function(node) { // console.log(node); if (node.type === 'number' && (node.hasAttribute('max') || node.hasAttribute('min'))) { node.setAttribute('maxlength', Math.max(node .getAttribute('max') && node.getAttribute('max').length || 0, node .getAttribute('min') && node.getAttribute('min').length || 0)); } if (node.hasAttribute('maxlength')) { _.add_listener('change', limit_input_maxlength, node); if (false) { // useless @ Chrome/61.0.3163.100 _.add_listener('keydown', limit_input_maxlength_onkeydown, node, true); } else { if (!node.onkeydown) node.onkeydown = check_input_onkeydown; if (false && !node.oninput) node.oninput = check_input_onkeydown; } } if (node.hasAttribute('pattern')) { var validator = node.getAttribute('pattern'); try { // e.g., "\d*" validator = new RegExp('^' + validator + '$'); node.validator = validator; if (!node.onkeydown) node.onkeydown = check_input_onkeydown; if (false && !node.oninput) node.oninput = check_input_onkeydown; } catch (e) { library_namespace.error({ T : [ 'Invalid pattern: %1', validator ] }); } } }, // "input[type="number"][maxlength]" 'input'); }; // 2007/4/25-27 0:48:22 RFC 3492 IDNA Punycode 未最佳化 // http://stackoverflow.com/questions/183485/can-anyone-recommend-a-good-free-javascript-for-punycode-to-unicode-conversion // http://xn-punycode.com/ function Punycode() { } Punycode.map = 'abcdefghijklmnopqrstuvwxyz0123456789'; Punycode.Dmap = 0; Punycode.base = Punycode.map.length; Punycode.tmin = 1; Punycode.tmax = 26; Punycode.skew = 38; Punycode.damp = 700; // 偏移 Punycode.initial_bias = 72; // 128 Punycode.initial_n = 0x80; // the default ACE prefix Punycode.prefix = "xn--"; Punycode.delimiter = '-'; Punycode._b = Punycode.base - Punycode.tmin; // Punycode._t = (Punycode._b * Punycode.tmax) >> 1; Punycode._t = Math.floor(Punycode._b * Punycode.tmax / 2); // IDNA ToASCII Punycode.encodeDomain = function(UURL) { var m = UURL.match(/^([\w\-]+:\/\/)?([^\/]+)/), UDomain = m ? m[2] : '', i = (m = UDomain) ? UURL .indexOf(m) : 0; if (false) document.write('<hr />Punycode.encodeDomain UDomain: [' + i + '][' + m + ']<br />'); if (m && m.replace(/[\x01-\x7f]+/g, '')) m = m.replace(/([^.]+)\./g, function($0, $1) { if (false) document.write($1 + '→' + encode($1) + '<br />'); return Punycode.prefix + Punycode.encode($1) + '.'; }), UURL = encodeURI(UURL.slice(0, i) + m + UURL.slice(i + UDomain.length)); return UURL; }; // IDNA ToUnicode Punycode.decodeDomain = function(PURL) { var m = PURL.match(/^([\w\-]+:\/\/)?([^\/]+)/), PDomain = m ? m[2] : '', i = (m = PDomain) ? PURL .indexOf(m) : 0; if (false) document.write('<hr />Punycode.decodeDomain PDomain: [' + i + '][' + m + ']<br />'); if (m) { m = m.replace(new RegExp(Punycode.prefix + '([^.]+)\\.', 'g'), function($0, $1) { if (false) document.write($1 + '→' + Punycode.decode($1) + '<br />'); return Punycode.decode($1) + '.'; }); if (m != PDomain) { PURL = PURL.slice(0, i) + m + PURL.slice(i + PDomain.length); try { PURL = decodeURI(PURL); } catch (e) { PURL = unescape(PURL); } } } return PURL; }; Punycode.adapt = function(delta, numpoints, firsttime) { if (false) document.write('*adapt: ' + delta + ', ' + numpoints + ', ' + firsttime + ', _b=' + _b + ', _t=' + _t + '<br />'); delta = // Math.floor(delta/(firsttime?damp:2)); firsttime ? Math.floor(delta / Punycode.damp) : delta >> 1; delta += Math.floor(delta / numpoints); var k = 0; for (; delta > _t; k += Punycode.base) delta = Math.floor(delta / Punycode._b); return k + Math.floor((Punycode._b + 1) * delta / (delta + Punycode.skew)); }; Punycode.encode = function(UString) { var n = Punycode.initial_n, cA = [], m, mA = [], i = 0, c, q, delta = 0, bias = Punycode.initial_bias, output = UString .replace(/[^\x01-\x7f]+/g, ''), h = output.length, b = h; if (false) document.write('<hr />Punycode.encode begin: [' + output + ']<br />'); if (b) output += Punycode.delimiter; for (; i < UString.length; i++) { cA.push(c = UString.charCodeAt(i)); if (c > n) mA.push(c); } mA.sort(library_namespace.descending); while (h < cA.length) { // 預防重複 do { c = mA.pop(); } while (m == c); m = c; if (false) if (m - n > (Number.MAX_VALUE - delta) / (h + 1)) { alert('Punycode: overflow'); return; } // should test overflow delta += (m - n) * (h + 1); n = m; for (i = 0; i < cA.length; i++) { // fail on overflow if (false) if (c = cA[i], c < n && !++delta) { alert('Punycode: overflow'); return; } if (c = cA[i], c < n) ++delta; if (false) document.write('<b>' + UString.charAt(i) + ' ' + (c.toString(16) + ',' + n.toString(16)) .toUpperCase() + '</b><br />'); if (c == n) { for (q = delta, k = Punycode.base;; k += Punycode.base) { t = k <= bias/* +Punycode.tmin: not needed */? Punycode.tmin : k >= bias + tmax ? Punycode.tmax : k - bias; if (q < t) break; output += Punycode.map.charAt(t + (q - t) % (Punycode.base - t)); if (false) document.write('<b>' + output + '</b><br />'); q = Math.floor((q - t) / (base - t)); } output += Punycode.map.charAt(q); bias = Punycode.adapt(delta, h + 1, h == b); if (false) document.write('h=' + h + '/' + cA.length + ', bias=' + bias + ', ' + output + '<br />'); delta = 0, h++; } } delta++, n++; } if (false) document.write(UString + '→' + output + '<br />'); return output; }; Punycode.decode = function(PCode) { var n = Punycode.initial_n, i = 0, p = PCode .lastIndexOf(Punycode.delimiter), bias = Punycode.initial_bias, output = p == -1 ? '' : PCode.slice(0, p), oldi, w, digit, l; if (false) document.write('<hr />Punycode.decode begin: [' + output + ']<br />'); if (!Punycode.Dmap) for (w = 0, Punycode.Dmap = {}; w < Punycode.map.length; w++) { Punycode.Dmap[Punycode.map.charAt(w)] = w; if (false) document.write('Punycode.Dmap[' + Punycode.map.charAt(w) + ']=' + w + '<br />'); } while (p < PCode.length - 1) { for (oldi = i, w = 1, k = Punycode.base;; k += Punycode.base) { if (++p >= PCode.length) { alert('Punycode: invalid input: out of range'); return PCode; } if (false) document.write('PCode.charAt(' + p + ')' + ' = ' + PCode.charAt(p) + ' → ' + Punycode.Dmap[PCode.charAt(p)] + '<br />'); if (isNaN(digit = Dmap[PCode.charAt(p)])) { alert('Punycode: invalid input'); return PCode; } if (false) if (digit > (Number.MAX_VALUE - i) / w) { alert('Punycode: overflow'); return; } i += digit * w; t = k <= bias/* +Punycode.tmin: not needed */? Punycode.tmin : k >= bias + Punycode.tmax ? Punycode.tmax : k - bias; if (false) document.write('i=' + i + ', t=' + t + ', digit=' + digit + ', k=' + k + '<br />'); if (digit < t) break; if (false) if (w > Number.MAX_VALUE / (base - t)) { alert('Punycode: overflow'); return; } w *= Punycode.base - t; } bias = Punycode.adapt(i - oldi, l = output.length + 1, oldi == 0); if (false) document.write('bias=' + bias + ', n=' + n + ', i=' + i + ', l=' + l + '<br />'); if (false) if (i / l > Number.MAX_VALUE - n) { alert('Punycode: overflow'); return; } n += Math.floor(i / l); i %= l; if (false) document .write('[' + output.length + ']' + output + '+' + n + '(0x' + n.toString(16).toUpperCase() + ')@' + i + '→'); output = output.slice(0, i) + String.fromCharCode(n) + output.slice(i); if (false) document.write('[' + output.length + ']' + output + '<br />'); i++; } if (false) document.write(PCode + '→' + output + '<br />'); return output; }; if (false) { var testC = 'Hello-Another-Way--fc4qua05auwb3674vfr0b', rC; document .write('<hr />' + // Punycode.encodeDomain('http://國際.計畫.org/國際.計畫.htm') Punycode .decodeDomain('http://xn--9cs229l.xn--gpyr35b.org/%E5%9C%8B%E9%9A%9B.%E8%A8%88%E7%95%AB.htm') // Punycode.encode('463578') + Punycode.decode('ihqwcrb4cv8a8dqg056pqjye') + '<hr />' + Punycode.encode('他们为什么不说中文') + Punycode.decode('ihqwctvzc91f659drss3x8bo0yb') + '<hr />' + Punycode.encode('他們爲什麽不說中文') + '<hr />' + (rC = Punycode.decode(testC)) + '<hr />' + (rC = Punycode.encode(rC)) + '<hr />' + (testC == rC ? 'OK' : '<b style="color:red">FAILED</b>:<br />' + testC + '<br />' + rC)); } /** * <code> 一個非常不好的 handle onload 方法。只在onload不具有arguments時有用,應該亦可用setTimeout('~',0) where 0:back,1:front for IE: <!--[if IE]><script defer type="text/javascript"> // onload code </script><![endif]--> c.f. http://www.brothercake.com/ http://simonwillison.net/2004/May/26/addLoadEvent/ GO1.1 Generic onload by Brothercake window.addEventListener,document.addEventListener,typeof window.attachEvent c.f. setTimeout('~',0); 不過這不能確定已經load好 </code> */ if (false) { var addonload = function(s, where) { if (!s || typeof window != 'object') return 1; if (typeof s == 'function') { s = library_namespace.parse_function(s); if (!s || !s.funcName) return 2; s = s.funcName + '()'; } var o = window.onload ? typeof window.onload == 'string' ? window.onload : library_namespace.parse_function(window.onload).contents : ''; window.onload = new Function(where ? s + ';\n' + o : o + ';\n' + s); } } _// JSDT:_module_ .DOM_loaded = function() { if (winodow.document.readyState === "complete" || winodow.document.body) { _.DOM_loaded = function() { return true; }; return true; } return false; }; if (false) { // The DOM ready check for Internet Explorer try { document.documentElement.doScroll('left'); } catch (e) { setTimeout(arguments.callee, 50); return; } } _// JSDT:_module_ . /** * 比較好點的 add onload。 比起 add_listener(),本函數在已經 load 時依然會執行,而 add_listener * 因為是用榜定的方法,因此 load 完就不再觸發(?)。 這東西頂多只能擺在 include 的 JS file 中,不能 runtime * include。 * * @example <code> CeL.run('net.web'); CeL.on_load(function(){sl(1);},'sl(2);'); </code> * * @requires _.add_listener,_.DOM_loaded * @see jQuery: $(document).ready(listener); DOMContentLoaded * http://webdesign.piipo.com/jquery/jquery_events 可直接參考 SWFObject。 * TODO: <a href="http://javascript.nwbox.com/IEContentLoaded/" * accessdate="2010/6/3 11:15" title="IEContentLoaded - An alternative * for DOMContentLoaded on Internet Explorer">IEContentLoaded</a> * DOMContentLoaded是firefox下特有的Event, 當所有DOM解析完以後會觸發這個事件。 * DOMContentLoaded與DOM中的onLoad事件與其相近。但onload要等到所有頁面元素加載完成才會觸發, * 包括頁面上的圖片等等。 <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> * $(document).ready(fn)發生在"網頁本身的HTML"載入後就觸發,而$(window).load(fn)則會等到"網頁HTML * 標籤中引用的圖檔、內嵌物件(如Flash)、IFrame"等拉哩拉雜的東西都載入後才會觸發。 * @_memberOf _module_ */ on_load = function on_load() { var _s = _.on_load, loaded = _.DOM_loaded(), i = 0, a = arguments, l = a.length; for (; i < l; i++) if (loaded) a[i].call(document); else _.add_listener('load', a[i], document); }; _// JSDT:_module_ . /** * bind/add listener. register event control, setup code to run. listener * 應該加上 try{}catch{},否則會搞不清楚哪裡出問題。 ** 對同樣的 object,事件本身還是會依照 call * add_listener() 的順序跑,不會因為 p_first 而改變。 ** NOT TESTED!! TODO: * remove_listener(): .removeEventListener(); .detachEvent(); default 'this' * 自訂 event * * @param {string}type * listen to what event type. event name/action. * http://www.whatwg.org/specs/web-apps/current-work/#event-handler-event-type * @param listener * listener function/function array/function string, 須 String 之 * recursive function 時可 "(function(){return function * f(){f();};})()" 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;} * @param [target_element] * bind/attach to what HTML element * @param [p_first] * parentNode first * @return * @since 2010/1/20 23:42:51 * @see c.f., GEvent.add_listener() * @_memberOf _module_ */ add_listener = function add_listener(type, listener, target_element, p_first) { // _s: self var _s = _.add_listener, i, adder; // 進階功能. // type is Object or Array. if (library_namespace.is_Object(type) || Array.isArray(type)) { // type is Object: // usage: add_listener({unload:Unload},target_element); // usage: // add_listener({load:{true:[function(){sl(1);},'sl(2);']}},target_element); // type is Array: // usage: // add_listener([{load:load},{unload:Unload}],target_element); // 此時 listener 已被忽略,shift arguments。 if (!(listener = get_element(listener))) return; for (i in type) { library_namespace.debug(i + ': ' + type[i], 2, 'add_listener'); Array.isArray(type) ? _s(type[i], listener, target_element) : _s(i, type[i], listener, target_element); } return; } if (!type || !listener) return; if (typeof listener === 'string') listener = new Function('e', listener); if (typeof target_element === 'string') target_element = get_element(target_element); if (typeof p_first !== 'boolean') p_first = typeof p_first === 'undefined' ? _s.p_first : !!p_first; // listener is Array or Object. if (library_namespace.is_Object(listener) || Array.isArray(listener)) { // usage: add_listener('unload',{true:Unload1}); // usage: add_listener('unload',[Unload1,Unload2]); // 因為 Array 會從最小的開始照順序出,所以這邊不再判別是否為 Array。 for (i in listener) { if (false) if (isNaN(f) // ||i==1||i===true ) { sl('add_listener: to ' + i); _s.p_first = i === 'true'; } _s(type, listener[i], target_element, i === 'true' || (i === 'false' ? false : undefined)); if (false) sl((typeof i) + ' [' + i + '] ' + _s.p_first); } } else if (library_namespace.is_Function(listener)) { /** * 先設定好 native listener adding function */ if (target_element) adder = target_element.addEventListener; else if (!(adder = _s.global_adder) && adder !== null) _s.global_adder = adder = _s.get_adder(); // $(document).ready(listener); // 使 listener 能以 this 取得 target_element i = function(e) { // this_event if (!e) e = window.event; if (false) library_namespace.debug('fire ' + type, 0, 'add_listener'); // 正規化 <a // href="http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#interface-Event">Document // Object Model (DOM) Level 3 Events</a>. // 這邊的附加設定應盡量只添上 native object, 預防 memory leak. if (!e.currentTarget) e.currentTarget = target_element; if (!e.target) e.target = e.srcElement || target_element; // from fix in jQuery // check if target is a textnode (safari) if (e.target && e.target.nodeType === TEXT_NODE) e.target = e.target.parentNode; // Add relatedTarget, if necessary if (!e.relatedTarget && e.fromElement) e.relatedTarget = e.fromElement === e.target ? e.toElement : e.fromElement; // 取得滑鼠座標 // http://hartshorne.ca/2006/01/23/javascript_cursor_position/ // http://hartshorne.ca/2006/01/18/javascript_events/ if (isNaN(e.pageX) && !isNaN(e.clientX)) { var s = get_window_status.scroll(); e.pageX = e.clientX + s[0] - s[2]; e.pageY = e.clientY + s[1] - s[3]; } // .call: 使 listener 可以用 'this' 來指涉 element return listener.call(target_element, e); }; // 主要核心動作設定之處理 // TODO: 在 onload 時使 target_element = null if (false) sl(type + ' (' + ((typeof p_first == 'undefined' ? _s.p_first : !!p_first) ? 'p_first' : 'run first') + '): ' + listener); if (adder) { try { // 直接用 target_element.addEventListener 不會有問題。 // .call(window.document): // for Chrome 'Illegal invocation' issue // http://stackoverflow.com/questions/1007340/javascript-function-aliasing-doesnt-seem-to-work // 但 IE9 需要 .call(target_element) 或者別用 .call,否則會得到 "Invalid // procedure call or argument" adder.call(target_element, type, i, p_first); } catch (e) { adder.call(window.document, type, i, p_first); } return; } if (target_element) { if (false) library_namespace .warn('add_listener: Cannot get element.addEventListener! element.attachEvent: ' + target_element.attachEvent); } return target_element && (adder = target_element.attachEvent) ? // http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx adder('on' + type, i) // : _s.default_adder(type, i, p_first, target_element); } }; _// JSDT:_module_ . /** * useCapture: parentNode first * * @see <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>, <a * href="http://www.w3.org/TR/DOM-Level-3-Events/#interface-EventTarget" * accessdate="2010/4/16 22:42">Interface EventTarget</a> */ add_listener.p_first = false; _// JSDT:_module_ . /** * get (native) global listener adding function. TODO: 只設定一次 historical for * Netscape Navigator, mozilla: window.captureEvents, document.captureEvents */ add_listener.get_adder = function() { /** * moz (gecko), safari 1.2, ow5b6.1, konqueror, W3C standard: * window.addEventListener * * @ignore * @see <a * href="https://developer.mozilla.org/en/DOM/element.addEventListener" * accessdate="2010/4/16 22:35">element.addEventListener - MDC</a> * <a href="http://simonwillison.net/2004/May/26/addLoadEvent/" * accessdate="2010/4/16 22:36">Executing JavaScript on page load</a> */ return window.addEventListener /** * opera 7.50, ie5.0w, ie5.5w, ie6w: window.attachEvent opera 7.50: * document.attachEvent */ || typeof window.attachEvent === 'function' && function(type, listener) { window.attachEvent('on' + type, listener); } /** * MSN/OSX, opera 7.50, safari 1.2, ow5b6.1: * document.addEventListener */ || document.addEventListener /** * ie5m, MSN/OSX, ie5.0w, ie5.5w ie6w: * document.onreadystatechange */ || null; }; _// JSDT:_module_ . /** * 最原始的,含括其他情況。 all: window.onload. TODO: use queue * * @param type * listen to what event type * @param listener * listener function/function array * @param [p_first] * parentNode first * @param [target_element] * bind/attach to what HTML element * @return * @see http://blog.othree.net/log/2007/02/06/third-argument-of-addeventlistener/ */ add_listener.default_adder = function(type, listener, p_first, target_element) { if (!target_element) target_element = window; var old = target_element[type = 'on' + type]; if (false) library_namespace.debug('adder ' + type + (old ? ' with old listener: ' + old : ''), 0, 'add_listener.default_adder'); return target_element[type] = old ? // TODO: typeof old === 'string' p_first ? function(e) { if (!e) e = window.event; if (false) library_namespace.debug('fire ' + type + ' (parentNode first)', 0, 'add_listener.default_adder'); old.call(target_element, e); listener.call(target_element, e); } : function(e) { if (!e) e = window.event; if (false) library_namespace.debug( 'fire ' + type + ' (parentNode latter)', 0, 'add_listener.default_adder'); listener.call(target_element, e); old.call(target_element, e); } : function(this_event) { if (false) library_namespace.debug('fire ' + type, 0, 'add_listener.default_adder'); listener.call(target_element, this_event || window.event); }; }; _// JSDT:_module_ . /** * TODO: listener list. 當無法執行 DOM 操作時(尚未載入、版本太舊不提供支援等)以此為主。 * add_listener.list[node][event type]=[listener list] */ add_listener.list = Object.create(null); _// JSDT:_module_ . /** * TODO: 觸發函數. 當無法執行 DOM 操作時(尚未載入、版本太舊不提供支援等)以此為主。 * add_listener.list[type]=[listener list] */ add_listener.list = Object.create(null); _// JSDT:_module_ . /** * 阻止 JavaScript 事件冒泡傳遞,使 event 不傳到 parentNode。 * * @param {Event}event * event handler * @param {Boolean}cancel * cancel bubble * @see http://www.jb51.net/html/200705/23/9858.htm * @_memberOf _module_ */ stop_event = function(event, cancel) { if (!event) event = window.event; if (typeof event.preventDefault === 'function') { // 在拖曳時可阻止預定動作,例如跳頁展示圖片或檔案。 event.preventDefault(); } else { event.returnValue = false; } if (cancel) { // cancelBubble 在IE下有效,stopPropagation 在 Firefox 下有效。 // 停止冒泡,事件不會上升,我們就可以獲取準確的鼠標進入元素。 http://realazy.org/lab/bubble/ if (typeof event.stopPropagation === 'function') { // IE9 & Other Browsers event.stopPropagation(); } else { // IE8 and Lower event.cancelBubble = true; } } // for using in <a> return false; }; // comparator([key, original index]) function sort_nodes(node_list, comparator, key_generator) { if (typeof key_generator !== 'function') key_generator = function(n) { return n; }; var i = 0, length = node_list.length, list = []; for (; i < length; i++) list.push([ key_generator(node_list[i]), i ]); list.sort(comparator); // 依照次序排列 nodes。 // TODO: 採用 .insertBefore() 時的最佳演算法,最小化(最少化).insertBefore() 操作。 // 找出 sort 後之連續 node list,有需要更動時才改。 // TODO: 最佳化 table list。 // TODO: 先 hide 是否會較快? for (i = 0; i < length; i++) { } } _// JSDT:_module_ . /** * 獲取頁面上選中的選取區資訊。 * * @example <code> 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); * </code> * * @param {Number} * [index] TODO: 第幾選取區, default: all or 0 if there's only * ONE/ZERO selection * @return {Object} { left: {Number} in px, top: {Number} in px, width: * {Number} in px, height: {Number} in px, text: {String} 文字, * element: {HTMLElement}, selection: selection object (browser * dependent) } * @return {undefined} error. * @see http://plugins.jquery.com/project/selectedText, Gecko: * https://developer.mozilla.org/en/DOM/Selection * @_memberOf _module_ */ get_selection = function(index) { }; try { if (window.getSelection) _.get_selection = function(index) { // Firefox, Opera, Safari // http://help.dottoro.com/ljcvonpc.php // Although the selection object is supported by Opera, it is // only partially suppported. The window.getSelection method // provides more complex functionality in that browser. // http://www.dotvoid.com/2001/03/using-the-range-object-in-mozilla/ var e = document.activeElement, // 在 Opera 中,e 為 [object Text] tag = e && e.tagName && e.tagName.toLowerCase(), s = window .getSelection(); if (!s.rangeCount) // 點擊而無選擇? // 最起碼回應能得知的資訊 return { text : '', element : s, selection : s }; // 超出範圍可能會 Error: INDEX_SIZE_ERR: DOM Exception 1 s = s.getRangeAt(!isNaN(index) && 0 <= index && index < s.rangeCount ? index : 0); // Gecko: https://developer.mozilla.org/en/DOM/range // 除了 Gecko 外,都有 s.getBoundingClientRect 但無 // s.endContainer.getBoundingClientRect。 // Gecko 可以取 mouse event 作 workaround if (false) library_namespace.debug(s.endContainer.parentNode); var offset = _.get_node_offset(s.getBoundingClientRect ? s : s.endContainer.parentNode); return { // TODO: offset // TODO: do test // s.startOffset, left : offset.left, top : offset.top, // s.endOffset, width : offset.width, height : offset.height, text : tag === 'textarea' || tag === 'input' || tag === 'select' ? e.value.substring( e.selectionStart, e.selectionEnd) : s.toString(), element : // s.endContainer s, selection : s }; }; else if (document.selection && document.selection.createRange) { // Internet Explorer // http://msdn.microsoft.com/en-us/library/ms534692%28VS.85%29.aspx // TODO: http://help.dottoro.com/ljefwsqm.php document.execCommand && document.execCommand('MultipleSelection', true, true); _.get_selection = function(input) { var s = document.selection.createRange(); return s.type !== 'None' && { // TODO: do test // http://msdn.microsoft.com/en-us/library/ms535872%28v=VS.85%29.aspx // s.offsetLeft, s.offsetTop 較不準 left : s.boundingLeft, top : s.boundingTop, width : s.boundingWidth, height : s.boundingHeight, text : s.text, // TODO // element: null, selection : s }; }; } else if (document.getSelection) _.get_selection = function(input) { return { // TODO: get offset from mouse location text : document.getSelection() }; }; } catch (e) { // TODO: handle exception } // ↑HTML only ------------------------------------------------------- var is_IE = /* @cc_on!@ */!true; // http://www.real-blog.com/programming/259 // http://fettig.net/weblog/2006/10/09/detecting-ie7-in-javascript/ if (false) if (typeof window.XMLHttpRequest != "undefined") { // IE 7, mozilla, safari, opera 9 } else { // IE6, old browsers } /** * <code> http://www.cnlei.org/blog/article.asp?id=337 在IE下: >> 支持keyCode >> 不支持which和charCode,二者值為 undefined 在Firefox下: >> 支持keyCode,除功能鍵外,其他鍵值始終為 0 >> 支持which和charCode,二者的值相同 在Opera下: >> 支持keyCode和which,二者的值相同 >> 不支持charCode,值為 undefined </code> */ _// JSDT:_module_ . /** * 條碼器(Barcode Scanner)/雷射讀碼器的輸入可用 onkeypress 取得 * * @param callback * callback * @return * @since 2008/8/26 23:10 * @example <code> * // usage: * deal_with_barcode(function(t) { * if (t.length > 9 && t.length < 17) * document.getElementById("p").value = t, * document.forms[0].submit(); * }); * </code> * * @_memberOf _module_ */ deal_with_barcode = function(callback) { var k, lt = 0, st = 0; document.onkeypress = function(this_event) { var c = new Date(); if ( // 前後不超過 800, c - st > 800 || // 與上一輸入不超過 90 c - lt > 90) { st = c; k = ""; } lt = c; c = this_event || window.event; c = c.keyCode || c.which || c.charCode; if (c > 32 && c < 120) k += String.fromCharCode(c); else if (c == 13) callback(k, this_event); }; }; // https://addons.mozilla.org/js/search-plugin.js // TODO, & Chrome function add_engine() { // NYI throw 'TODO'; } // for string encoding // ------------------------------------------------------- var HTML_Entities_predefined = { quot : '"', amp : '&', apos : "'", lt : '<', gt : '>' }, HTML_Entities_predefined_values = Object .values(HTML_Entities_predefined), // @see // https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references HTML_Entities = Object.assign({ nbsp : ' ', iexcl : '¡', cent : '¢', pound : '£', curren : '¤', yen : '¥', brvbar : '¦', sect : '§', uml : '¨', copy : '©', ordf : 'ª', laquo : '«', not : '¬', shy : '­', reg : '®', macr : '¯', deg : '°', plusmn : '±', sup2 : '²', sup3 : '³', acute : '´', micro : 'µ', para : '¶', middot : '·', cedil : '¸', sup1 : '¹', ordm : 'º', raquo : '»', frac14 : '¼', frac12 : '½', frac34 : '¾', iquest : '¿', Agrave : 'À', Aacute : 'Á', Acirc : 'Â', Atilde : 'Ã', Auml : 'Ä', Aring : 'Å', AElig : 'Æ', Ccedil : 'Ç', Egrave : 'È', Eacute : 'É', Ecirc : 'Ê', Euml : 'Ë', Igrave : 'Ì', Iacute : 'Í', Icirc : 'Î', Iuml : 'Ï', ETH : 'Ð', Ntilde : 'Ñ', Ograve : 'Ò', Oacute : 'Ó', Ocirc : 'Ô', Otilde : 'Õ', Ouml : 'Ö', times : '×', Oslash : 'Ø', Ugrave : 'Ù', Uacute : 'Ú', Ucirc : 'Û', Uuml : 'Ü', Yacute : 'Ý', THORN : 'Þ', szlig : 'ß', agrave : 'à', aacute : 'á', acirc : 'â', atilde : 'ã', auml : 'ä', aring : 'å', aelig : 'æ', ccedil : 'ç', egrave : 'è', eacute : 'é', ecirc : 'ê', euml : 'ë', igrave : 'ì', iacute : 'í', icirc : 'î', iuml : 'ï', eth : 'ð', ntilde : 'ñ', ograve : 'ò', oacute : 'ó', ocirc : 'ô', otilde : 'õ', ouml : 'ö', divide : '÷', oslash : 'ø', ugrave : 'ù', uacute : 'ú', ucirc : 'û', uuml : 'ü', yacute : 'ý', thorn : 'þ', yuml : 'ÿ', OElig : 'Œ', oelig : 'œ', Scaron : 'Š', scaron : 'š', Yuml : 'Ÿ', fnof : 'ƒ', circ : 'ˆ', tilde : '˜', Alpha : 'Α', Beta : 'Β', Gamma : 'Γ', Delta : 'Δ', Epsilon : 'Ε', Zeta : 'Ζ', Eta : 'Η', Theta : 'Θ', Iota : 'Ι', Kappa : 'Κ', Lambda : 'Λ', Mu : 'Μ', Nu : 'Ν', Xi : 'Ξ', Omicron : 'Ο', Pi : 'Π', Rho : 'Ρ', Sigma : 'Σ', Tau : 'Τ', Upsilon : 'Υ', Phi : 'Φ', Chi : 'Χ', Psi : 'Ψ', Omega : 'Ω', alpha : 'α', beta : 'β', gamma : 'γ', delta : 'δ', epsilon : 'ε', zeta : 'ζ', eta : 'η', theta : 'θ', iota : 'ι', kappa : 'κ', lambda : 'λ', mu : 'μ', nu : 'ν', xi : 'ξ', omicron : 'ο', pi : 'π', rho : 'ρ', sigmaf : 'ς', sigma : 'σ', tau : 'τ', upsilon : 'υ', phi : 'φ', chi : 'χ', psi : 'ψ', omega : 'ω', thetasym : 'ϑ', upsih : 'ϒ', piv : 'ϖ', ensp : ' ', emsp : ' ', thinsp : ' ', zwnj : '‌', zwj : '‍', lrm : '‎', rlm : '‏', ndash : '–', mdash : '—', lsquo : '‘', rsquo : '’', sbquo : '‚', ldquo : '“', rdquo : '”', bdquo : '„', dagger : '†', Dagger : '‡', bull : '•', hellip : '…', permil : '‰', prime : '′', Prime : '″', lsaquo : '‹', rsaquo : '›', oline : '‾', frasl : '⁄', euro : '€', image : 'ℑ', weierp : '℘', real : 'ℜ', trade : '™', alefsym : 'ℵ', larr : '←', uarr : '↑', rarr : '→', darr : '↓', harr : '↔', crarr : '↵', lArr : '⇐', uArr : '⇑', rArr : '⇒', dArr : '⇓', hArr : '⇔', forall : '∀', part : '∂', exist : '∃', empty : '∅', nabla : '∇', isin : '∈', notin : '∉', ni : '∋', prod : '∏', sum : '∑', minus : '−', lowast : '∗', radic : '√', prop : '∝', infin : '∞', ang : '∠', and : '∧', or : '∨', cap : '∩', cup : '∪', int : '∫', there4 : '∴', sim : '∼', cong : '≅', asymp : '≈', ne : '≠', equiv : '≡', le : '≤', ge : '≥', sub : '⊂', sup : '⊃', nsub : '⊄', sube : '⊆', supe : '⊇', oplus : '⊕', otimes : '⊗', perp : '⊥', sdot : '⋅', lceil : '⌈', rceil : '⌉', lfloor : '⌊', rfloor : '⌋', lang : '〈', rang : '〉', loz : '◊', spades : '♠', clubs : '♣', hearts : '♥', diams : '♦' }, HTML_Entities_predefined); // 可適用perl: HTML::Entities::encode_entities() // 需要escape的: [\<\>\"\'\%\;\)\(\&\+], tr/A-Za-z0-9\ //dc // http://www.cert.org/tech_tips/malicious_code_mitigation.html _// JSDT:_module_ . /** * Translate HTML code to Unicode text. 將 HTML:&#ddd; → Unicode text * * @param {String} * HTML HTML code * @param {Object}[options] * 附加參數/設定選擇性/特殊功能與選項 or {Boolean}only_numeric * @returns * @_memberOf _module_ * * @see function escape_ampersand(text) @ CeL.application.storage.EPUB */ HTML_to_Unicode = function HTML_to_Unicode(HTML, options) { if (options === true) { options = { entity : true, numeric : true }; } else if (!options) { options = { predefined : true, entity : true, numeric : true }; } else { options = library_namespace.setup_options(options); } // 使用\0可能會 Warning: non-octal digit in an escape sequence that // does not // match a back-reference var unicode_text = HTML.valueOf(); if (options.is_URI) { try { // 必須先採用 decodeURIComponent(), // CeL.HTML_to_Unicode() 往後的程式碼僅為了解碼 &#*。 // 否則: // CeL.DOM.HTML_to_Unicode('%EF%BC%BB %EF%BC%BD') // !== decodeURIComponent('%EF%BC%BB %EF%BC%BD') unicode_text = decodeURIComponent(unicode_text); } catch (e) { // URIError: URI malformed } } // -------------------------------------- // numeric character references function convert_digital(all, digital) { // digital: o 之版本 if (digital > 0x10FFFF) return all; var char = String.fromCodePoint(digital); return !options.predefined // && HTML_Entities_predefined_values.includes(char) ? all : char; } function convert_hex(all, hex) { //  之版本 var digital = parseInt(hex, 16); return convert_digital(all, digital); } if (options.numeric) { // decodeURIComponent() unicode_text = unicode_text // \d{2,8}: 比起所允許的7位數多一位數,預防在不是以 ";" 為結尾的情況下,有無效數字。 .replace(/�*(\d{2,8});?/g, convert_digital) // ";?": Allow CeL.HTML_to_Unicode(' ABC') .replace(/&#[xX]0*([\dA-Fa-f]{2,6});?/g, convert_hex); // .replace(): JScript 5.5~ if (false && options.is_URI) { // 2022/5/10 6:22:20 一般HTML中的%dd不會被解碼。 // is_URI 已經在前面處理完了,看起來根本不需要這一段。 unicode_text = unicode_text.replace(/%([\dA-Fa-f]{2})/g, convert_hex); } } // -------------------------------------- // named character references, named entities if (options.entity) { // HTML Entities (HTML character entity) // "∳" unicode_text = unicode_text.replace(/&([a-z]\w{0,49});/ig, // function(entity, name) { return (options.predefined // || !(name in HTML_Entities_predefined)) // && (name in HTML_Entities) ? HTML_Entities[name] // : entity; // name = name.toLowerCase(); }); } return unicode_text; }; _.HTML_to_Unicode.entities = HTML_Entities; _// JSDT:_module_ . /** * Translate Unicode text to HTML * * @param {String} * text Unicode text * @param mode * mode='x':&#xhhh; * @return {String} HTML * @_memberOf _module_ */ to_HTML = function(text, mode) { var html = '', t, i = 0; for (; i < text.length; i++) { t = text.charCodeAt(i); html += '&#' + (mode === 'x' ? 'x' + t.toString(16) : t) + ';'; } return html; }; _// JSDT:_module_ . /** * Translate Unicode text to HTML code. escape chars * * @param text * Unicode text * @param flags * flags, f&1!=0: turn \t, (f&2)==0: \n→<br />, f==4: to quoted * @param ignore_tags * e.g., * {object:{src:/^https?:\/\//},img:{src:/^https?:\/\//},a:{href:/^https?:\/\//}} * @return * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML * @_memberOf _module_ */ Unicode_to_HTML = function(text, flags, ignore_tags) { text = ('' + text) // "&"這個字元得要首先escape .replace(/&/g, '&') // 就是會出現這奇怪情況。但是卻也不能否認有特別想要表示"&"這樣的情況。 // .replace(/&amp;/g, '&') .replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); if (ignore_tags) text = text.replace(/<([^>]+)>/g, function($0, $1) { if (!($1 in ignore_tags)) return '<' + $1; var s = $1.split(/ /), // i = 1, l = s.length, c = ignore_tags[$1]; for (; i < l; i++) { m = s[i].match(/^([^=]+)(.+?)/); if (!(m[1] in c) || !(library_namespace.is_type(c[m[1]], 'RegExp') && c[m[1]].test(m[2]) || library_namespace .is_Function(c[m[1]]) && c[m[1]](m[2]))) s[i] = ''; return s.join(' '); } }); else text = text.replace(/</g, '<'); if (flags == 4) return text; text = text.replace(/ /g, ' '); // if (!f) f = 0; if (flags & 1) text = text.replace(/ /g, '<span style="margin-left:3em;"> </span>'); if (!(flags & 2)) { text = text.replace(/(\r?\n)/g, '<br />$1') // +'<br />\n' ; } return text; }; // Ucode: \uhhhh及\xhh之意 _ // JSDT:_module_ .Unicode_unescape = function(U) { var T = U.replace(/\\\\|\\u005[cC]|\\x5[cC]|\\134/g, "\0"); if (false) { // way 1 T = T.replace(/\\u([\dA-Fa-f]{4})/g, function($0, $1) { return String.fromCharCode(parseInt($1, 16)); }).replace(/\\x([\dA-Fa-f]{2})/g, function($0, $1) { return String.fromCharCode(parseInt($1, 16)); }).replace(/\\([0-7]{1,3})/g, function($0, $1) { return String.fromCharCode(parseInt($1, 16)); }); // way 2 T = T.replace(/\\(u[\dA-Fa-f]{4}|x[\dA-Fa-f]{2})/g, function($0, $1) { return String.fromCharCode(parseInt($1.substr(1), 16)); }).replace(/\\([0-7]{1,3})/g, function($0, $1) { return String.fromCharCode(parseInt($1, 16)); }); } // way 3 T = T.replace(/\\(u[\dA-Fa-f]{4}|x[\dA-Fa-f]{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)); }); if (T.indexOf("\\") != -1) T = T.replace(/\\t/g, "<Tab>").replace(/\\n/g, "<Line Feed>") .replace(/\\v/g, "<Vertical Tab>").replace(/\\f/g, "<Form Feed>").replace(/\\r/g, "<Carriage Return>") .replace(/\\(.)/g, "$1"); return T.replace(/\0/g, "\\"); }; _// JSDT:_module_ . // Unicode escape sequence // TODO: 效能 Unicode_escape = function(text, max_code) { var i = 0, U = '', t; if (isNaN(max_code)) max_code = 256; for (; i < text.length; i++) U += (t = text.charCodeAt(i)) < max_code ? text.charAt(i) : "\\u0000".substr(0, 6 - (t = t.toString(16)).length) + t; return U; }; function CSSToTxt(C) { return C.replace(/\\\\|\\0{0,4}5[cC][ \t\r\n\f]?/g, "\0").replace( /\\([\dA-Fa-f]{1,6})[ \t\r\n\f]?/g, function($0, $1) { return String.fromCharCode(parseInt($1, 16)); }).replace(/\\(.)/g, "$1").replace(/\0/g, "\\"); } function TxtToCSS(T, r, sp) { // r:radio,sp:separator var i = 0, C = '', t, p = r && r > 3 && r < 9 ? '0'.repeat(r - 1) : ''; if (!sp) sp = ''; sp += '\\'; for (; i < T.length; i++) { t = T.charCodeAt(i).toString(16); // (p&&r>t.length?p.substr(0,r-t.length):''):如果length是0或負值,會傳回空字串。 C += sp + p.substr(0, r - t.length) + t; } return C.slice(sp.length - 1); } _// JSDT:_module_ . /** * Translate a query string to a native Object contains key/value pair set. * * @param {String} * query_string query string. default: location.search * @param {Object} * add_to append to this object * @return key/value pairs * @type Object * @since 2010/6/16 15:18:50 * @_memberOf _module_ * @see */ get_query = function(query_string, add_to) { if (!query_string) query_string = window/* self */.location.search.slice(1); else if (typeof query_string !== 'string') { // TODO } var i, q = query_string.replace(/\+/g, ' ').split('&'), p, s = add_to || Object.create(null), k, v; for (i in q) try { if (p = q[i].match(/^([^=]*)=(.*)$/)) { k = decodeURIComponent(p[1]); v = decodeURIComponent(p[2]); if (k in s) if (typeof s[k] === 'string') s[k] = [ s[k], v ]; else s[k].push(v); else s[k] = v; } else s[decodeURIComponent(q[i])] = undefined; } catch (e) { // TODO: handle exception } return s; }; _// JSDT:_module_ . /** * Translate a native Object contains key/value pair set to a query string. * TODO: 增進效率。 * * @param {Object} * query_Object query Object. * @return {String} query string * @type String * @_memberOf _module_ * @see jQuery.param */ to_query_string = function(query_Object) { if (!library_namespace.is_Object(query_Object)) return; var name, query_list = []; for (name in query_Object) query_list.push(encodeURIComponent(name) + '=' + encodeURIComponent(query_Object[name])); return query_list.join('&'); }; /** * 簡化 HTML (word)。 simplify HTML. * * 目標:剩下語意部分,去掉 style。 * * TODO: 保留 b, em */ var has_RegExp_group = false; try { has_RegExp_group = (new RegExp('(\\d)\\1')).test('00'); } catch (e) { } // 保留 color: return style string to add // reduce_HTML.keep_color = reduce_HTML._keep_color = function(c) { if (c !== 'black') return c; }; reduce_HTML.file = function(FP, enc) { // sl('reduce_HTML [' + FP + ']'); var t = simpleRead(FP, enc || simpleFileAutodetectEncode), l; if (!t) { error('Open [' + FP + '] failed.'); return; } l = t.length; t = this(t); FP = FP.replace(/\.[xs]?html?$/i, function($0) { return '.reduced' + $0; }); if (false) sl('reduce_HTML: ' + l + '→' + t.length + ' (' + parseInt(100 * t.length / l) + '%)' + ', save to [<a href="' + encodeURI(FP) + '">' + FP + '</a>].'); simpleWrite(FP, t, 'utf-8'); }; function reduce_HTML(t) { if (!t) return; var _f = reduce_HTML, f = function($0, $1, $2) { return $1 != $2 || ($1.toLowerCase() in { a : 1, p : 1, head : 1 }) ? $0 : ''; }; if (false) { if (m = t.match(/<!--\[if [^\]]+\]>[\s\S]*?<!\[endif\]-->/)) sl(m[0].replace(/</g, '<')); if (m = t.match(/<!\[if !vml\]>[\s\S]*?<!\[endif\]>/)) sl(m[0]); } t = t .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('') : '') + '>'; }) .replace(/<\?xml:namespace[^>]+>/g, '') .replace(/[\s\n]*(<\/t[dh]>)[\s\n]*/ig, '$1') .replace(/<wbr[^>]*>/ig, '<br />') .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] + '"' : '') + '>'; }) .replace( /<(span|font|p|div|b|u|i)[\s\n]+([^>]*)>/ig, function($0, $1, $2) { var t = '<' + $1, s = '', m; if ( // /Italic/i.test($2) $2.indexOf('Italic') !== -1) s += 'font-style:italic;'; // TODO: <u>, <b> if (_f.keep_color && (m = $2 .match(/[\s\n;"'][\s\n]*color[\s\n]*:[\s\n]*([^\s\n;"']+)/)) && (m = _f.keep_color(m[1]))) // 保留 color s += 'color:' + m + ';'; return t + (s ? ' style="' + s + '"' : '') + '>'; }) .replace(/<(tr|table)[\s\n]+([^>]*)>/ig, '<$1>') // 不能用 .+|\n ,IE8 sometimes crash .replace(/<span>([\s\S]*?)<\/span>/ig, '$1') // need several times .replace(/<span>([\s\S]*?)<\/span>/ig, '$1') .replace(/<font>([\s\S]*?)<\/font>/ig, '$1') // 2 times .replace(/<([a-z\d]+)>[\s\n]*<\/([a-z\d]+)>/ig, f) .replace(/<([a-z\d]+)>[\s\n]*<\/([a-z\d]+)>/ig, f) .replace(/<o:p>([\s\S]*?)<\/o:p>/ig, '$1') .replace(/<st1:[^>]+>([\s\S]*?)<\/st1:[^>]+>/ig, '$1') .replace(/<!\[if !vml\]>([\s\S]*?)<!\[endif\]>/ig, '$1') .replace(/<o:SmartTagType [^>]+\/>/ig, '') /** * <code> <td> <p> </p> </td> </code> */ .replace( /<(span|p|div|t[dr])([^>]*>)<(span|p)>(([\s\n]+| )*?)<\/(span|p)><\/(span|p|div|t[dr])>/ig, '<$1$2$4</$7>') .replace(/[\s\n]*<\/p>([\s\n]*<br\s*\/?>)*[\s\n]*<p[^>]*>/ig, '<br />\n') .replace( /<link rel=(File-List|colorSchemeMapping|themeData|Edit-Time-Data)[^>]+>/ig, '') .replace(/^[\s\n]*<\html[^>]*>[\s\n]*/, '<\html>') .replace(/[\s\n]*<\body[^>]+>[\s\n]*/, '<\body>') .replace( /[\s\n]*<!--\[if [^\]]+\]>[\s\S]*?<!\[endif\]-->(\r?\n)*/ig, '').replace( /[\s\n]*<\style[^>]*>[\s\S]*?<\/style>[\s\n]*/ig, '') .replace(/[\s\n]*<\meta[\s\n][^>]+>[\s\n]*/ig, '') // from HTML_to_Unicode() // 預防 error 之版本 .replace(/�*(\d{2,7});/ig, function($0, $1) { return $1 > 0x10FFFF ? $0 : String.fromCharCode($1); }).replace(/([\s\n]+| )+$|^([\s\n]+| )+/g, ''); if (has_RegExp_group) { t = t.replace(/<([bis])[\s\n]*>([^<]*)<\/\1>([\s\n]*)<\1>/ig, '$2'); } if (/<(img|table)[>\s\n]/.test(t)) { library_namespace.debug('Has table or images.'); t = t .replace( /<\/head>/i, '<\style type="text/css">table,th,td{border:1px solid #888;border-collapse:collapse;}img{border:0;max-width:99%;}</style></head>'); } return t; } ; /** * 傳回 element's data-* attributes 相對應帶有連字符號的 name。 * * @param {String}[name] * dataset name. * * @returns {String} element's data-* attributes 相對的 name。 * * @since 2012/11/9 23:15:30 */ function to_hyphenated(name) { if (library_namespace.is_debug() && /-[a-z]/.test(name)) throw new SyntaxError( 'The dataset name "' + name + '" contains a U+002D HYPHEN-MINUS character (-) followed by a lowercase ASCII letter.'); // 'data-': dataset prefix. return 'data-' + name.replace(/[A-Z]/g, function($0) { return '-' + $0.toLowerCase(); }); } /** * 設定 dataset。<br /> * 以 node.dataset 為準,node.attributes 為輔。<br /> ** 注意: IE8 中無法設定 <title> 之 * .dataset,會被忽略掉。即使從 .outerHTML 亦無法取得。 * * @example <code> * // get value * CeL.DOM_data(node, name); * * // set value * CeL.DOM_data(node, name, value); * * // delete value * CeL.DOM_data(node, name, undefined); * </code> * * @param {HTMLElement}node * 所指定之 node。 * @param {String|Object}[name] * dataset name. * @param [value] * 設成 undefined 時,將 delete 此 name。 * * @returns value of dataset[name] * * @since 2012/11/9 23:15:30 */ function dataset_compatible(node, name, value) { if (!node || node.nodeType === TEXT_NODE) // IE8 中,甚至不能設定 node.dataset,會出現 "物件不支援此屬性或方法"。 return; if (!node.dataset) // initialization. // 給予個預設值,省略判斷,簡化流程。 node.dataset = Object.create(null); if (!name) { // get all dataset. return dataset_synchronize(node); return node.dataset; } var d = node.dataset; if (arguments.length > 2) { // need to set value. if (value === undefined) delete d[name]; else d[name] = String(value); // 同步。保證全程使用此函數時,同時也會設定好 the element's data-* attributes。 if (value === undefined) node.removeAttribute(to_hyphenated(name)); else node.setAttribute(to_hyphenated(name), value); } else if (library_namespace.is_Object(name)) { // 此時 name = { name : value }; // 因為並非單純的指定到 .dataset,因此不用 Object.assign()。 for ( var n in name) dataset_compatible(node, n, name[n]); return node.dataset; } else if ((value = node.getAttribute ? node .getAttribute(to_hyphenated(name)) : node[to_hyphenated(name)]) !== undefined) { // 同步。 d[name] = String(value); } return d[name]; } /** * 同步 / synchronize / update / prepare dataset。<br /> // * https://github.com/remy/polyfills/blob/master/dataset.js // * https://github.com/eligrey/Xccessors We won't use * Element.prototype.__defineGetter__('dataset', ...): IE 7 have no * Object.prototype.__defineGetter__ or Object.defineProperty. * * TODO: remove attribute. * * @param {HTMLElement}node * 所指定之 node。 * @param {Boolean}[from_attributes] * from the element's data-* attributes.<br /> * 預設為 dataset ↔ attribute。設定此 flag 將會作單向設定。 * * @since 2012/11/9 23:35:30 */ function dataset_synchronize(node, from_attributes) { if (!node || node.nodeType === TEXT_NODE) // IE8 中,甚至不能設定 node.dataset,會出現 "物件不支援此屬性或方法"。 return; var d = node.dataset, name; // if (!d) return; // assert: node.dataset 已經設定好了。 if (from_attributes === undefined || from_attributes) { library_namespace.debug('attribute → dataset.', 2, 'dataset_synchronize'); for_attributes(node, function(name, value) { // library_namespace.debug('attribute → dataset: test [' + // name // + '].', 2, 'dataset_synchronize'); if (name = name.match(/^data-([^A-Z]+)$/)) d[name[1].replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); })] = value; }); if (false) { for (var i = 0, attributes = node.attributes, length = attributes.length, attribute; i < length; i++) { if (false) library_namespace.debug('attribute → dataset: test [' + i + '][' + attributes[i].name + '].', 2, 'dataset_synchronize'); if (name = (attribute = attributes[i].name) .match(/^data-([^A-Z]+)$/)) { d[name[1].replace(/-([a-z])/g, function($0, $1) { return $1.toUpperCase(); })] = node.getAttribute(attribute); } } } } if (!from_attributes) { library_namespace.debug('dataset → attribute.', 2, 'dataset_synchronize'); for (name in d) node.setAttribute(to_hyphenated(name), d[name]); } return d; } // http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#dom-dataset // http://dev.w3.org/html5/spec/single-page.html#dom-dataset // detect dataset support. var support_dataset, dataset; try { // Element.prototype.__lookupGetter__("dataset") _.support_dataset = support_dataset = library_namespace.is_WWW(true) && library_namespace.is_type(document.body.dataset, 'DOMStringMap'); } catch (e) { } if (support_dataset) dataset = function(node, name, value) { var d = node.dataset; // test node has NO .dataset if (!name || !d) return d; if (arguments.length > 2) if (value === undefined) delete d[name]; else // String(value): for Symbol value d[name] = String(value); else if (library_namespace.is_Object(name)) { // 此時 name = { name : value }; for ( var n in name) d[n] = name[n]; return d; } return d[name]; }; else { // The browser does not support dataset! library_namespace .debug('The runtime environment does not support dataset!'); dataset = dataset_compatible; } _.DOM_data = dataset; // ↑for string encoding ----------------------------------------------- /** {Boolean}support CSS position sticky */ var CSS_position_sticky = library_namespace.platform({ firefox : 32, chrome : 56, safari : 5 }), is_Safari = library_namespace.platform({ safari : 5 }); /** * 動態[生成/顯示][目錄/目次]。<br> * automatically generated menu / list / table of contents.<br> * TODO: fix dataset bug. mouseover → popup TOC. * * @example <code> CeL.run([ 'application.locale', 'interact.DOM' ], function() { CeL.gettext.use_domain('', function() { CeL.auto_TOC(); }); }); * </code> * * @param {String|HTMLElement}[content_node] * 針對指定 node 列出目錄。 * @param {Object}[options] * 附加參數/設定特殊功能與選項 */ function auto_TOC(content_node, options) { options = library_namespace.setup_options(options); /** {Integer}to <h\d>. default: 6. */ var level = options.level; /** {Integer}0:auto, 1:re-show, 2: force show. */ var force = options.force; if (!(content_node = get_element(content_node))) content_node = document.body; if (!force && content_node.scrollHeight < 4 * screen.height) return; // 設定目錄 height。 function set_height() { if (!CSS_position_sticky) { return; } if (node.style.position) { TOC_list.style.height = ''; return; } var height = window.innerHeight; if (!isNaN(height) // 當 TOC_list 的高度超出可見區域時,方縮小之。 && (height = (height - 40) | 0) < TOC_list.offsetHeight) { TOC_list.style.height = height + 'px'; } } function add_TOC_node(node) { library_namespace.debug('<' + node.tagName + '>\n' + node.innerHTML.slice(0, 200), 3); head_array.push(node); title = set_text(node); // l: title 長度在規範內。 i = title.length < auto_TOC.max_length; // l: tagName // CSS 分大小寫。 l = node.tagName.toLowerCase(); if (!node.id && !node.name) { node.id = encodeURIComponent(title); if (false) { // from wiki node.id = node.id.replace(/%/g, '.').replace(/\s/g, ''); } } // 實際上應該用<li>,但<h\d>可能不會有 nested 層疊結構。 list_array.push({ div : { a : i ? title : [ title.slice(0, auto_TOC.max_length), { span : '..', C : auto_TOC.CSS_prefix + 'more' } ], href : href + (node.id || node.name), // subtitle R : (i ? '' : title + (node.title ? '\n' : '')) + (node.title || ''), target : '_self', onclick : function() { // 先緊縮目錄。 toggle_display(TOC_list, false); } }, C : auto_TOC.CSS_prefix + l + (l === 'header' ? '' : ' ' + auto_TOC.CSS_prefix + 'header') }); } var list_array = [], head_array = [], node = content_node.firstChild, matched, title, i, l, // Chrome 22 在遇上 /p/cgi.cgi?_=_ 時,僅指定 href : #~ 會變成 /p/#~。因此需要 // workaround。 href = location.href.replace(/#.*$/, '') + '#'; if (is_Safari) { // encodeURI(): Safari 5.1.7 needs this. // But Opera will broken on this. href = encodeURI(href); } level |= 0; level = new RegExp('^(h[1-' + (level >= 1 && level <= 6 ? level : 6) + ']|header)$', 'i'); while (node) { if ((matched = node.tagName) && matched.match(level)) add_TOC_node(node); // 表層遍歷。 // TODO: 增加對更深層的探索。 node = node.nextSibling; } if (list_array.length === 0) // <h2> 為最常利用之中級結構。 for_nodes(add_TOC_node, 'h2'); if (list_array.length > 1) { var TOC_list, id = set_attribute(content_node, 'id'), // gettext_config:{"id":"↑back-to-toc"} back_title = gettext('↑Back to TOC'); title = set_attribute(content_node, 'title'); if (!title) { node = content_node.firstChild; // 當 firstChild 為 <header> 時,採用其內容為標題。 if (/^h[1-3]$/i.test(node.tagName)) title = set_text(node); } if (!title) title = id; id = auto_TOC.CSS_prefix + (id || Math.random()); TOC_list = id + '_list'; // 回來修改各 <header> for (i = 0, l = head_array.length; i < l; i++) { if (false && i > 0) { // Firefox/38.0 在兩個 hade 相鄰的情況,anchor 似乎無法正常作動。 // 只好手動助之加入 <p> // ** 無用! 需於 <html> 中手動加入! matched = node.nextSibling; while (matched.nodeType === TEXT_NODE) matched = matched.nextSibling; if (matched === head_array[i]) new_node({ p : ' ' }, [ node, 3 ]); } set_class(node = head_array[i], auto_TOC.CSS_prefix + 'head'); new_node({ a : '📑', href : href + id, C : auto_TOC.CSS_prefix + 'back', // T : '↑Back to TOC', R : back_title, target : '_self' // TODO: element 本身可能是浮動的,因此應跳到下一個內文本文的元素,並採用 // .nextElementSibling.scrollIntoView()。 // @see function go_to_anchor(anchor) @ reviews.original.js }, [ node, 1 ]); } list_array = [ // 設定目錄定位。 { span : [ { span : CSS_position_sticky ? auto_TOC.icon.unpin : '', onclick : function() { node.style.position = node.style.position // ? '' : 'static'; this.innerHTML = auto_TOC.icon[ // node.style.position ? 'pin' : 'unpin']; set_height(); }, // gettext_config:{"id":"pin-unpin-the-toc"} R : 'Pin/unpin the TOC' }, { span : auto_TOC.icon.right, onclick : function() { node.style.cssFloat = node.style.cssFloat // ? '' : 'right'; this.innerHTML = auto_TOC.icon[ // node.style.cssFloat ? 'left' : 'right']; }, // gettext_config:{"id":"set-toc-to-left-or-right"} R : 'Set TOC to left or right' } ], C : auto_TOC.CSS_prefix + 'position_control' }, { // U+1F4D1 BOOKMARK TABS // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=128000 // http://www.fileformat.info/info/emoji/list.htm // http://codepoints.net/U+1F4D1 div : [ '📑', { // gettext_config:{"id":"contents-of-$1"} T : title ? [ 'Contents of [%1]', options.title_name // && options.title_name(title) || title ] // gettext_config:{"id":"contents"} : 'Contents' } ], C : auto_TOC.CSS_prefix + 'control', // gettext_config:{"id":"expand"} title : gettext('expand'), onclick : function() { var expand_now = toggle_display(TOC_list) !== 'none'; // show/hide (顯示/隱藏), 展開/收合目錄 click to expand // gettext_config:{"id":"collapse"} this.title = gettext(expand_now ? 'collapse' // gettext_config:{"id":"expand"} : 'expand'); if (expand_now) set_height(); } }, { div : list_array, id : TOC_list, C : auto_TOC.CSS_prefix + 'list' } ]; var class_name = auto_TOC.CSS_prefix // 若是不具有此屬性,則明確指定不使用此屬性;預防有瀏覽器雖然已實現此屬性,但是並沒有被本函式庫偵測出來。 + (CSS_position_sticky ? 'box' : 'box_no_sticky'); if (node = get_element(id)) { _.remove_all_child(node); set_class(node, class_name); new_node(list_array, node); } else { node = new_node({ div : list_array, id : id, C : class_name }, [ content_node, 1 ]); } // auto_TOC.set_text(id); // 作 cache。 TOC_list = get_element(TOC_list); // 載入 CSS resource(s)。 // include resources of module. library_namespace.run(library_namespace.get_module_path( module_name, 'auto_TOC.css')); } else library_namespace.warn('auto_TOC: No ' + level + ' found.'); // Release memory. 釋放被占用的記憶體. head_array = list_array = null; } // title 最大長度 in px。 auto_TOC.max_length = 80; // CSS class name 前綴。 auto_TOC.CSS_prefix = 'TOC_'; // TODO: set domain auto_TOC.set_text = function(id) { // 目錄 gettext.translate_nodes(get_element(id).childNodes); // ↑回到目錄 gettext.translate_nodes('.' + auto_TOC.CSS_prefix + 'back'); }; auto_TOC.icon = { pin : '⚓', unpin : '⇧', left : '⇦', right : '⇨' }; _// JSDT:_module_ .auto_TOC = auto_TOC; // ---------------------------------------------------------------------// function random_color(from, gap) { function scale(from, gap) { return from + (Math.random() * gap) | 0; } from |= 0; if (from < 0 || from > 255) from = 0; if (!gap) gap = 256 - from; var color = [], i = 3; while (i--) color.push(scale(from, gap)); return 'rgb(' + color + ');'; } function parse_frame(document_node) { function parse_frameset(frameset) { var nodes = frameset.childNodes, i = 0, length = nodes.length, tag, list = [], cols = frameset.cols .trim(), cell, node, background = random_color(210), // get_info = function() { var name = node.name + '(' + layout.shift() + ')'; return node.src ? { b : name, title : node.src } : name; }, // IE 先看 cols,之後才看 rows。 layout = (cols || frameset.rows.trim()).split(/\s*,\s*/); // cols = !!cols; for (; i < length; i++) { if ((tag = (node = nodes[i]).tagName) && (cell = (tag = tag.toLowerCase()) === 'frame' ? { a : get_info(), href : '#', onclick : function() { // application.debug.show_value first if (library_namespace.show_value) // Error null: 462 [Error] (facility // code // 10): 遠端伺服器不存在或無法使用 try { library_namespace.show_value(this, this.id || this.name); } catch (e) { library_namespace.error(e); } else { library_namespace.warn( // 'Need to include application.debug first!' // + ' Trying now...'); library_namespace.run('application.debug'); } return false; }.bind(node) } : tag === 'frameset' && [ { div : get_info(), S : 'width:100%;color:#e73;background-color:' // + background + ';' }, parse_frameset(node) ])) { cell = { td : cell, S : 'background-color:' + background + ';' }; list.push(cols ? cell : { tr : cell }); } } return { table : { tbody : cols ? { tr : list } : list }, S : 'width:100%;border-collapse:collapse;' }; } try { // IE 只會取第一個 <frameset>。 var frameset = document_node.getElementsByTagName('frameset')[0]; if (frameset) library_namespace.log(parse_frameset(frameset)); else if (library_namespace.is_debug()) library_namespace.warn('No frameset detected.'); } catch (e) { library_namespace.error(e); } } _.parse_frame = parse_frame; return (_// JSDT:_module_ ); }