UNPKG

cejs

Version:

A JavaScript module framework that is simple to use.

1,147 lines (939 loc) 35.8 kB
/** * @name CeL 下拉式表單 function * @fileoverview 本檔案包含了下拉選擇式表單的 functions。 * * @example<code> TODO: HTML 5 <datalist> Tag date http://plugins.jquery.com/project/timepicker http://digitalbush.com/projects/masked-input-plugin/ 理想: http://gs.statcounter.com/ http://plugins.jquery.com/search/node/Autocomplete+type%3Aproject_project http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/ http://jsgears.com/thread-114-1-1.html set focus/blue background-image instead of HTML 5 placeholder text http://dev.w3.org/html5/spec/Overview.html#the-placeholder-attribute The placeholder attribute represents a short hint (a word or short phrase) intended to aid the user with data entry. e.g., background-image: url(http://www.google.com/cse/intl/en/images/google_custom_search_watermark.gif); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: 0% 50%; background-repeat: no-repeat no-repeat; or http://perldoc.perl.org/ usually show a <div>. show <input> only at focus. http://miketaylr.com/pres/html5/forms2.html http://people.opera.com/brucel/demo/html5-forms-demo.html http://www.erichynds.com/examples/jquery-multiselect/examples.htm http://x.wawooo.com/archives/891 http://www.google.com.tw/dictionary 鍵盤選擇時同時改變值 </code> * * @since */ //'use strict'; typeof CeL === 'function' && CeL.run( { name: 'interact.form.select_input', // for new URL(url) require: 'interact.DOM.get_node_offset|application.net.', code: module_code }); function module_code(library_namespace, load_arguments) { // requiring var get_node_offset = this.r('get_node_offset'); // 載入 CSS resource(s)。 // include resources of module. library_namespace.run(library_namespace.get_module_path(this.id, 'select_input.css')); /** * 簡易型 interact.DOM.XML_node @ interact.form.select_input * @param tag * p.appendChild tag * @param p * parent node * @param t * text * @param classN * className * @inner * @ignore * @return */ var create_DO = function (tag, p, t, classN) { var _e; if (t && (typeof t != 'object' || library_namespace.is_Object(t))) t = document.createTextNode('' + t); if (typeof tag === 'object') { _e = tag; } else if (tag) { _e = document.createElement(tag); if (classN) _e.className = classN; if (t // 真有出錯應該改源頭… // && t.nodeType ) { _e.appendChild(t); } } else if (t) _e = t; if (p && _e) p.appendChild(_e); return _e; }; /** * get scrollbar height * * @return * @since 2008/9/3 23:31:21 * @inner * @ignore * @see http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php<br /> * lazy evaluation * http://peter.michaux.ca/articles/lazy-function-definition-pattern */ function scrollbar_width() { var _f = scrollbar_width; if (!_f.w) { var w, p = create_DO('div', document.body), c = create_DO('div', p, ' '), s = p.style; s.width = s.height = '80px'; // 有時沒這行才出得來 // c.style.width = '100%'; s.overflow = 'hidden'; w = c.offsetWidth; s.overflow = 'scroll'; _f.w = w - c.offsetWidth; library_namespace.debug('scrollbar_width: ' + w + '-' + c.offsetWidth + '=' + _f.w, 2); document.body.removeChild(p); } return _f.w; } /** * scroll 到可以看到 object TODO: 考慮可能沒 scrollbar 包括橫向 * * @param o * object * @param [p] * parentNode to scroll * @return * @since 2008/9/3 23:31:29 * @inner * @ignore */ function scroll_to_show(o, p) { if (!p) { p = o; while ((p = p.parentNode) && p.offsetHeight == p.scrollHeight) ; } library_namespace.debug('scroll_to_show: ' + p.scrollTop + ', ' + p.scrollHeight + ',' + p.offsetHeight + ', ' + o.offsetTop, 2); var s, a; if (a = o.offsetTop, a < p.scrollTop) s = a; else if (a = o.offsetTop + o.offsetHeight - p.offsetHeight + scrollbar_width(), a > p.scrollTop) if (s = a, a = o.offsetTop, a < s) s = a; if (!isNaN(s)) p.scrollTop = s; } /** * <code> { title: '', name: '', container: 'id' | obj, list: [] | {} | {group1:{}, group2:[],.. }, default: '' | [], type: 'select' | 'radio' | 'checkbox', } return <select> TODO: 複選 <select> <radio> <checkbox> +<label> autocomplete: 假如所有備取 list 都有一樣的 prefix,則自動完成。 把後面的用反白自動完成。 在 list 上下安排三角,onmouseover 即可自動滾動。 color panel http://www.itlearner.com/code/js_ref/choi3.htm selectName.options[i]=new Options("option_value","option_Text", defaultSelected, selected); </code> */ /** * container object, list * @param o * @param l * @return * @inner * @ignore */ function menu_creater(o, l) { }; // =================================================== var // class private ----------------------------------- /* 可紀錄的 set class name,不過對大多數人來說,更常用的是 instance.setClassName usage: (item[, obj]) set obj to className item, return real className that assigned (0,'prefix') set prefix & 重設(全部重跑) */ setClassName = function (i, o, noRec) { // (0, prefix) or (item, object) var _t = this, s = _.classNameSet; if (!_t.assignedClass) _t.assignedClass = []; if (!o || typeof o === 'object') { // 設定並回傳 className library_namespace.debug('setClassName: test ' + 'class_' + i + ': ' + ('class_' + i in _t ? '<em>YES</em>' : 'none'), 2); s = [i in s ? s[i].charAt(0) === '~' ? s.prefix + s[i].slice(1) : s[i] : '' ]; if ('class_' + i in _t) if (i === 'error' || i === 'warning') s.unshift(_t['class_' + i]); else s.push(_t['class_' + i]); s = s.join(' '); library_namespace.debug('setClassName: set ' + o + (s ? ' to [' + s + ']' : ', <em>There is no [' + i + '] in classNameSet or instance set.</em>'), 2); if (o && (o.className = s, !noRec)) _t.assignedClass.push(s, o); return s; } s.prefix = o; o = _t.assignedClass; // 重設(全部重跑) for (var i = 0; i < o.length; i++) _f.call(_t, o[0], o[1], 1); }, funcButton = function (_t, t, f, title) { // add text t, function f to instance _t var _p = pv(_t), o = create_DO('span', _p.listO, '['), b; setClassName.call(_t, 'functionB', o); b = create_DO('span', o, t); setClassName.call(_t, 'functionT', b); b.title = title, b.onclick = f; create_DO(0, o, ']'); return b; }, // 簡易型 removeAllChild = function (o) { o.innerHTML = ''; return o; }, // show/hide list showList = function (show) { // ():get, 0:hide, 1:show var _t = this, _p = pv(_t), o = _p.listO, s, c = 0; if (!o) return; s = o.style; if (show) { c = get_node_offset(_p.inputO); s.top = c.top + c.height + 2 + 'px'; s.left = c.left + 'px'; s.width = c.width + 'px'; s.height = ''; // reset c = s.display = 'block'; if (_t.maxListHeight && o.offsetHeight > _t.maxListHeight) s.height = _t.maxListHeight + 'px'; } else if (typeof show != 'undefined') c = s.display = 'none'; if (c) create_DO(0, removeAllChild(_p.arrowO), _.textSet[c != 'none' ? 'hideList' : 'showList']); else c = s.display; return c != 'none'; }, /* 準備選擇清單的某一項 TODO: 自動完成 到最後若可能自動轉到全部 → */ cK = 0, // control key pressed readyTo = function (e, o) { if (!e) e = event; var _t = this, _p = pv(_t), c, gI = function (o) { return o && //(can_use_special_attribute ? o.getAttribute("sIndex") : o.sIndex) o.sIndex; }; library_namespace.debug('readyTo: ' + e.type + ', key: ' + (e.keyCode || e.which || e.charCode) + ', _p.listA: ' + (_p.listA && _p.listA.length), 2); if (!_p.listA || !_p.listA.length) return; if (e.type === 'mouseover' || e.type === 'mouseout') { if (_p.readyItem) setClassName.call(_t, 'item', _p.readyItem, 0); if (e.type === 'mouseover') c = 'item_select', _p.readyItem = o; else if (c = 'item', _p.readyItem === o) _p.readyItem = 0; // 需更改 _p.inputO.onkeyup 以防止重新 list!! } else if ((c = e.keyCode || e.which || e.charCode) === 13) { if (_p.readyItem) { library_namespace.debug('readyTo: 以鍵盤選擇: ' + _p.readyItem.innerHTML, 4); cK = c, _p.readyItem.onclick(); // 用 .click() 無效! return false; } else return; // key input 用鍵盤控制上下 ←↑→↓: 37~40 } else if (c == 38 || c == 40) { cK = c; o = _p.readyItem; library_namespace.debug('readyTo: 以鍵盤移至: ' + (o && (o.getAttribute("sIndex") + ',' + o.sIndex)), 4); if (!o) o = _p.listA[c == 40 ? 0 : _p.listA.length - 1]; else { // IE 可用 getAttribute,FF 或許在 appendChild 之後屬性重設?,得用 o.sIndex if (!o.getAttribute) throw 1; c = gI(o) + (c == 38 ? -1 : 1); if (c < 0 || c >= _p.listA.length) return; setClassName.call(_t, 'item', o, 0); o = _p.listA[c]; } _p.readyItem = o; scroll_to_show(o, _p.listO); c = 'item_select'; } else if (c == 35 || c == 36) { // 35: End, 36: Home cK = c; if (o = _p.readyItem) setClassName.call(_t, 'item', o, 0); _p.readyItem = o = _p.listA[c == 36 ? 0 : _p.listA.length - 1]; scroll_to_show(o, _p.listO); c = 'item_select'; } else if (c == 33 || c == 34) { // 33: PageUP, 34: PageDown cK = c; o = _p.readyItem; if (!o) return; setClassName.call(_t, 'item', o, 0); var i = gI(o), t; if (c == 33) { t = _p.listO.scrollTop - 1; while (i && _p.listA[i - 1].offsetTop > t) i--; } else { t = _p.listO.scrollTop + _p.listO.offsetHeight - scrollbar_width(); while (i < _p.listA.length - 1 && _p.listA[i + 1].offsetTop < t) i++; } library_namespace.debug('readyTo: Page: ' + i + ', top: ' + t + ', scroll: ' + _p.listO.scrollTop, 4); if (i == gI(o)) if (c == 33) { t -= _p.listO.offsetHeight; if (t < 2) i = 0; else while (i && _p.listA[i - 1].offsetTop > t) i--; } else { t += _p.listO.offsetHeight; while (i < _p.listA.length - 1 && _p.listA[i + 1].offsetTop < t) i++; } library_namespace.debug('readyTo: Page: ' + i + ', top: ' + t + ', height: ' + _p.listO.offsetHeight, 4); _p.readyItem = o = _p.listA[i]; scroll_to_show(o, _p.listO); c = 'item_select'; } else return; setClassName.call(_t, c, o, 0); return false; }, //can_use_special_attribute, // 顯示清單的工具函數 setList = function (l, force, limit, f) { var _t = this, _p = pv(_t), i, c = 0, k, o; if (isNaN(limit)) limit = isNaN(_t.maxList) ? _.maxList : _t.maxList || Number.MAX_VALUE; if (!f) f = function (l, i) { var a = _t.onList(l, i), o; if (!a) return; // a[0] 可能是 Array 之類。 o = create_DO('div', 0, String(a[0])); setClassName.call(_t, 'item', o); o.title = a[1]; k = a[2] || a[1]; o.onmouseover = o.onmouseout = function (e) { readyTo.call(_t, e, o); }; o.onclick = function () { var v = _t.onSelect(l, i); _t.setValue(v); _t.onInput(v); }; // 這邊本來放在下面 for 的地方 c++, _p.listO.appendChild(o); //if (!can_use_special_attribute) { o.setAttribute("sIndex", 1); can_use_special_attribute = o.getAttribute("sIndex") ? 1 : -1; } //if (can_use_special_attribute == 1) o.setAttribute("sIndex", _p.listA.length); else o.sIndex = _p.listA.length; //o.setAttribute("sIndex", o.sIndex = _p.listA.length); o.sIndex = _p.listA.length; _p.listA.push(o); return o; }; //_t.showList(0); _p.listO = removeAllChild(_p.listO); _p.listA = []; _p.readyItem = 0; if (Array.isArray(l)) { for (i = 0; i < l.length && c < limit; i++) f(l, i); } else for (i in l) if (c < limit) { f(l, i); } else break; library_namespace.debug('setList: list ' + c + ' items, key ' + k + '=?' + _t.setValue(), 2); if (c == 1 && _t.setValue() == k) { // 僅有一個且與 key 相同 c = 0; } if (!force && !c) { // 無 list return; } // add function if (c != _t.allListCount) funcButton(_t, _.textSet.allBtn, function () { _t.doFunc = 1; _t.focus(); _t.setList(_t.setAllList(), 1, Number.MAX_VALUE); }, '顯示全部 ' + _t.allListCount + ' 列表。'); if (_t.setValue()) funcButton(_t, _.textSet.clearBtn, function () { _t.doFunc = 2; _t.focus(); _t.onInput(_t.setValue('')); }, '清除輸入內容,重新列表。'); funcButton(_t, _.textSet.closeBtn, function () { _t.doFunc = 3; _t.showList(0); }, 'close menu \n關閉列表'); showList.call(_t, 1); return _t.listCount = c; }, // return verify 之後的 key(<input>) 值 do_verify = function (k) { var _t = this, c = _t.verify(k || _t.setValue()); library_namespace.debug('do_verify: input status: ' + (c == 1 ? 'warning' : c == 2 ? 'error' : 'OK'), 2); if (typeof c === 'string') { // 可以設定 key 值! k = c; _t.setValue(k, do_verify); } else { setClassName.call(_t, c == 1 ? 'warning' : c == 2 ? 'error' : 'input', pv(_t).inputO, 1); } return k; }, // 簡易設定常用的 onInput 型式 searchInList = function (f, o) { // o: 傳入 (list, index, key) var _t = this; if (typeof f === 'string' && (f in _.searchFunctionSet)) f = _.searchFunctionSet[f]; // 因為允許傳入 list,所以不能在這邊用 _t.setAllList() 判別函數,而得要寫一個泛用的。 return _t.onInput = function (key, list, force) { library_namespace.debug('searchInList, onInput: search [' + key + '] use ' + f, 2); if (!list) list = _t.setAllList(); key = do_verify.call(_t, key || ''); var l, i; library_namespace.debug('searchInList: search ' + (list instanceof Array ? 'array' : 'object'), 2); if (Array.isArray(list)) { l = [];//new list.constructor(); for (i = 0; i < list.length; i++) if (o ? f(list, i, key) : list[i] && f(list[i], key)) l.push(list[i]); // search value } else { l = {}; for (i in list) if (o ? f(list, i, key) : i && f(i, key) || list[i] && f(list[i], key)) l[i] = list[i]; // search key+value } _t.setList(l, force); }; }, /** * 切換 [input] / inputted [span] * @param {Boolean|undefined} to_input 切換至 input or not. default: 切換至 [input] * @return * @private * @inner * @ignore */ toggleToInput = function (to_input) { var _t = this, _p = pv(_t); if (to_input || typeof to_input === 'undefined') { // to <input> _p.inputtedO.style.display = 'none'; if (_t.allListCount) _p.arrowO.style.display = 'inline'; _p.inputO.style.display = 'inline'; return 1; } else { // to inputted <span> _t.showList(0); _t.setInputted(); if (to_input = library_namespace.get_style && parseInt(library_namespace.get_style(_p.inputO, 'width'))) { //library_namespace.debug(to_input); // TODO: +16, +10: magic number try { // .get_style(_p.arrowO, 'width') 可能回傳 'auto' @ IE8 _p.inputtedO.style.width = (to_input + parseInt(library_namespace.get_style(_p.arrowO, 'width')) + 16) + 'px'; _p.inputtedO.style.height = (parseInt(library_namespace.get_style(_p.inputO, 'height')) + 10) + 'px'; } catch (e) { // TODO: handle exception } } _p.arrowO.style.display = _p.inputO.style.display = 'none'; if (!_p.inputtedO.innerHTML) _p.inputtedO.innerHTML = '&nbsp;'; //_p.inputtedO.style.border = '3px #aaa dotted'; _p.inputtedO.style.display = to_input ? 'inline-block' : 'inline'; } }, // TODO: http://blog.xuite.net/sugopili/computerblog/17695447 set_source = function (URL) { ; }, /* 配置元件 本函數會配置/增加: <div> .container <input> .inputO <span> .inputtedO <span> .arrowO <div> .listO arguments: <input> 會被當作 inputO 主元件 <select> 會被當作選項 others: container */ layout = function (o) { var _t = this, _p = pv(_t), t; if (typeof o !== 'object') o = document.getElementById(o); if (!o || (o.tagName.toLowerCase() in { hr: 1, br: 1 })) return; // ** 這邊應該檢查 o 是不是 <hr /> 等不能加 child 的! //library_namespace.debug(('layout: use <' + o.tagName + (o.id ? '#' + o.id : '') + '>: ' + o.innerHTML).replace(/</g, '&lt;')); // TODO: 這邊應該有一個更完善的刪除策略 if (_t.loaded) { t = _p.container; // 不必多做功,已經達到所需配置了。 if (t === o.parentNode) return; for (var i = 0, e = 'inputO,inputtedO,arrowO,listO'.split(','); i < e.length; i++) { library_namespace.debug('layout: removeChild ' + e[i]); //t.removeChild(_p[e[i]]); _p[e[i]].parentNode.removeChild(_p[e[i]]); } if (!t.childNodes.length) t.parentNode.removeChild(t); } // 依照各種不同的傳入 object 作出應對 t = o.tagName.toLowerCase(); if (t === 'input') { try { // http://www.w3.org/TR/html5/forms.html#the-pattern-attribute // http://www.whatwg.org/specs/web-apps/current-work/#attr-input-pattern // http://www.w3school.com.cn/html5/html5_input.asp t = o.pattern || //o.getAttribute&& o.getAttribute('pattern'); // compiled as a JavaScript regular expression with the global, ignoreCase, and multiline flags disabled // somewhat as if it implied a ^(?: at the start of the pattern and a )$ at the end if (t && (t = new RegExp('^(' + t + ')?$'))) { //library_namespace.debug('set verify pattern of [' + o.id + ']: ' + t); _t.set_verify(t); } } catch (e) { library_namespace.error('error pattern: [' + t + ']'); library_namespace.error(e); } o.parentNode.insertBefore( t = _p.container = create_DO('span'), _p.inputO = o ); setClassName.call(_t, 'container', t); if (!o.className) setClassName.call(_t, 'input', o); t.appendChild(o.parentNode.removeChild(o)); o = t; } else if (t === 'select') { o.parentNode.insertBefore(t = _p.container = create_DO('span'), o); _p.inputO = create_DO('input', t); setClassName.call(_t, 'input', _p.inputO); _p.inputO.name = o.name; if (o.selectedIndex >= 0) _p.inputO.value = o.options[o.selectedIndex].value; var l = {}, opt = o.options, i = 0; for (; i < opt.length; i++) l[opt[i].value || opt[i].innerHTML] = opt[i].innerHTML; // list setting _t.setAllList(l); o.parentNode.removeChild(removeAllChild(o)); o = t; } else { // 容器 _p.container = o; if (!o.className) setClassName.call(_t, 'container', o); _p.inputO = create_DO('input', o); setClassName.call(_t, 'input', _p.inputO); } // 補足其他的設定 _p.inputO.setAttribute("autocomplete", "off"); _p.inputtedO = create_DO('span', o); setClassName.call(_t, 'inputted', _p.inputtedO); _p.inputtedO.style.display = 'none'; _p.inputtedO.onclick = function () { _t.clickNow = 1; _t.toggleToInput(); _p.inputO.focus(); _t.clickNow = 0; }; (_p.arrowO = create_DO('span', o, _.textSet.showList)) .title = _.textSet.arrowTitle; setClassName.call(_t, 'arrow', _p.arrowO); _p.listO = create_DO('div', o); _p.arrowO.onmouseover = _p.listO.onmouseover = function () { _t.clickNow = 1; }; _p.arrowO.onmouseout = _p.listO.onmouseout = function () { _t.clickNow = 0; }; setClassName.call(_t, 'list', _p.listO); _t.showList(0); // event setting //_p.inputO.onmouseover = _p.inputO.onkeydown = function (e) { readyTo.call(_t, e); }; _p.inputO.onmouseup = _p.inputO.onkeyup = _p.inputO.ondragend = function (e) { if (!e) e = event; var c = e.keyCode || e.which || e.charCode; library_namespace.debug('up: ' + e.type + ', key: ' + c + ', _p.listA: ' + (_p.listA && _p.listA.length), 2); if (cK && cK == c) { cK = 0; return false; } // Esc if (c == 27) { _t.showList(0); return false; } _t.clickNow = 1; _t.onInput(_t.setValue()); }; _p.inputO.onmouseout = function () { _t.clickNow = 0; }; if (_p.inputO.addEventListener) _p.inputO.addEventListener('dragdrop', _p.inputO.ondragend, false); //if (window.addEventListener) window.addEventListener('click', function () { _t.showList(0); }, true); //addListener(0, 'click', function () { sl('close..'); _t.showList(0); sl('close done.'); }) _p.inputO.onblur = function () { // 這在 Firefox 似乎沒啥效果.. //if (_t.verify(_t.setValue()) == 2) { alert('Wrong input!'); return false; } /* 設定這項在按 _p.arrowO 的時候會出問題,所以建議在其他地方自訂。 if (_t.setValue() && (_t.setValue() in _t.setAllList())) _t.toggleToInput(0); */ // TODO: 假如以鍵盤離開,應該也 showList(0); //library_namespace.debug('clickNow=' + _t.clickNow, 1, '_p.inputO.onblur'); if (_t.clickNow) _t.clickNow = 0; else _t.showList(0); }; // show/hide by press arrow _p.arrowO.onclick = function () { library_namespace.debug('arrowO.onclick start', 3); _t.clickNow = 1; if (_t.showList()) // 正在顯示就把他關起來 _t.showList(0); else // 沒在顯示就把他開起來: setValue 設定完 list,onInput 模擬 key-down _t.onInput(_t.setValue(), 0, 1); _t.clickNow = 0; library_namespace.debug('arrowO.onclick end', 3); }; // ondblclick: double click //_p.inputO.ondblclick = function () { _t.onInput(_p.inputO.value, 0, 1); }; _t.loaded = 1; // isLoaded }, // instance constructor --------------------------- instanceL = [], initI = function (o, l, s) { // (HTML object, list: Array or Object, onInput handler) var _t = this, _p; // objects setting if (typeof o != 'object') { //library_namespace.debug('Use object [' + o + ']'); o = document.getElementById(o); } _p = pv(_t); // also do initial instanceL.push(_t); // for destructor if (o) { layout.call(this, o); } else if (false) { throw new Error(1, 'Cannot get document object' + (o ? ' [' + o + ']' : '') + '!'); return; } // list setting if (l && !_t.allListCount) _t.setAllList(l); if (_p.arrowO) _p.arrowO.style.display = _t.allListCount ? 'inline' : 'none'; // 無 list 的話先不顯示,等有 list 再說。 // setup default inputted value _t.dInputted = _t.setValue; if (s) _t.setSearch(s); //return _t; }; //=================================================== /**<code> _ = this TODO: 浮水印 background-image:url(); HISTORY: 2008/7/22 0:38:14 create 7/27 22:55:18 verify() 8/7 21:18:47 attach() </code>*/ /** * 提供有選單的 input * @class form 的 functions * @see * http://dojocampus.org/explorer/#Dijit_Form%20Controls_Filtering%20Select_Basic */ var _// JSDT:_module_ = function () { initI.apply(this, arguments); typeof load_arguments === 'function' && load_arguments.apply(this, arguments); }, // (instance private handle) 不要 instance private 的把這函數刪掉即可。 _p = '_' + (Math.random() + '').replace(/\./, ''), // get private variables (instance[,destroy]), init private variables (instance[,access function list[, instance destructor]]) pv = function (i, d, k) { var V, K = _p('k'); return arguments.callee.caller === _p('i') ? (V = _p(i[K] = _p()), V.O = i, V.L = {}) : (K in i) && (V = _p(i[K])) && i === V.O ? d ? (_p(i[K], 1), delete i[K]) : V.L : {}; }; // (for inherit) 不要 inherit 的把這段刪掉即可。 //(_.clone = arguments.callee).toString = function () { return '[class_template]'; }; // class destructor --------------------------- /**<code> please call at last (e.g., window.unload) // usage: classT = classT.destroy(); // or if you has something more to do: classT.destroy() && classT= null; </code>*/ _.destroy = function () { for (var i = 0; i < instanceL.length; i++)instanceL[i].destroy(); _p(); }; // (instance private handle, continue) eval('_p=(function(_,pv,initI){var ' + _p + '={a:pv,d:_.destroy,c:0,k:"+pv+' + Math.random() + '",i:initI};return function(i,d){var f=arguments.callee.caller;if(f===' + _p + '.a){if(!d)return i in ' + _p + '?' + _p + '[i]:(' + _p + '[i=' + _p + '.c++]={},i);' + _p + '[i]={};}if(f===' + _p + '.d)' + _p + '={};}})(_,pv,initI);'); _p.toString = function () { return ''; }; /**<code> // 測試是否可用自訂之屬性 var o = document.createElement('div'); o.setAttribute('testA', 2); can_use_special_attribute = o.getAttribute('testA'); sl('can_use_special_attribute: ' + can_use_special_attribute); </code>*/ // class public interface --------------------------- // 預設清單最大顯示數 _.maxList = 10; // searchInList 常用到的函數 _.searchFunctionSet = { allTheSame: function (i, k) { return (i + '') === k; }, startWith: function (i, k) { return (i + '').slice(0, k.length) === k; }, // 不管大小寫 Whether the case startWithWC: function (i, k) { return (i + '').slice(0, k.length).toLowerCase() === k.toLowerCase(); }, includeKey: function (i, k) { return (i + '').toLowerCase().indexOf(k.toLowerCase()) !== -1; }, includeKeyWC: function (i, k) { return (i + '').toLowerCase().indexOf((k + '').toLowerCase()) !== -1; }, always: function () { return true; } }; // 預設 className 前有 ~ 的會轉成 prefix _.classNameSet = { prefix: 'si_', container: '~container', input: '~input', inputted: '~inputted', arrow: '~arrow', list: '~list', item: '~item', item_select: '~item_select', functionB: '~function', functionT: '~functionText', error: '~error', warning: '~warning' }; // 預設顯示文字 _.textSet = { showList: '▼', // 4 way: [▴▸▾◂] hideList: '▲', arrowTitle: 'toggle list \n切換顯示查詢列表', allBtn: '全部', clearBtn: '清除', closeBtn: '關閉'//'×' }; // default 欄位驗證 pattern // http://blog.wu-boy.com/2009/06/16/1454/ // TODO: ID, Age, 電話, 地址, 性別, ... // TODO: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern _.default_verify_pattern = { '|word': /^\w*$/, 'word': /^\w+$/, // 整數 '|integer': /^(?:[+\-]\d)?\d*$/, 'integer': /^[+\-]?\d+$/, // 自然數 '|natural': /^(?:[1-9]\d*)?$/, 'natural': /^[1-9]\d*$/, // 十進位小數 '|decimal': /^(?:[+\-]\d)?\d*(\.\d+)?$/, 'decimal': /^[+\-]?(?:\d+|\d*\.\d+)$/, // 數字 '|digit': /^\d*$/, 'digit': /^\d+$/, IPv4: /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/, URI: function (k) { //return !!library_namespace.URI(k); try { return !!new URL(k); } catch (e) { } }, // RFC 2822 // http://regexlib.com/DisplayPatterns.aspx //'RFC2822' : /^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/, // http://www.regular-expressions.info/email.html //'email' : /^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+([a-z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b$/i, email: /^[a-z0-9+_~-]+(\.[a-z0-9+_~-]+)*@([a-z\d]([a-z\d-]*[a-z\d])?\.)+([a-z]{2}|com|org|net)\b$/i, any: function (k) { return k === '' ? 2 : 0; } }; _.prototype = { // 應該盡量把東西放在 class,instance少一點? // instance public interface ------------------- /* click 事件進行中 TODO: 用更好的方法取代 */ clickNow: 0, // instance 的 <input>,.. 之 className, override _.classNameSet.input,.. //class_input : '~', //class_item : '~', //.. //maxList : \d, // 預設清單 height (px) maxListHeight: 200, // 設定/取得所有可選的 list setAllList: function (l) { var _t = this, _p = pv(_t), i, c = 0, s = _p.arrowO; _t.showList(0); if (typeof l === 'object') { _p.list = l; if (Array.isArray(l)) { // 這不準,得用 onList 測試。 c = _t.allListCount = l.length; } else { for (i in l) c++; _t.allListCount = c; } library_namespace.debug('setAllList: Get about ' + _t.allListCount + ' items.', 2); if (s) if (s = s.style, !c) s.display = 'none'; else if (_t.autoShowArrow) s.display = ''; } return _p.list; }, // 自動於有 list 時 show arrow,無時 hide autoShowArrow: 0, // 設定要顯現的 list,會回傳 list,需注意可能被更改! setList: function (l) { // key return setList.apply(this, arguments); }, showList: function (show) { return showList.apply(this, arguments); }, /* showArrow: function (show) { var a = pv(this).arrowO.style; if (typeof show != 'undefined') a.display = show ? '' : 'none'; return a.display; }, */ // 每次 input 就會被 call 一次。可用 instance.setSearch('includeKey') 簡易設定 onInput: function (k) { // key }, // 設定表單文字欄位的欄位驗證 return 1: warning, 2: error ('Suffering from a pattern mismatch'), string: 將輸入改為回傳值, else OK // 另外可設定 onkeypress(){return true/false;} 來對每一次按鍵作 check。但這不能處理 paste。 http://irw.ncut.edu.tw/peterju/jscript.html#skill verify: function (k) { // key }, set_verify: function (v) { var m = _.default_verify_pattern; if (library_namespace.is_Object(m) && (v in m)) v = m[v]; if (library_namespace.is_RegExp(v)) this.verify = function (k) { return v.test(k) ? 0 : 2; }; else if (typeof v === 'function') this.verify = v; else if (typeof v === 'string' && (m = v.match(/^(\d*)-(\d*)$/)) && (m[1] || m[2])) this.verify = new Function('k', 'return isNaN(k)' + (m[1] ? '||k<' + m[1] : '') + (m[2] ? '||k>' + m[2] : '') + ' ? 2 : 0;'); else library_namespace.error('error verify condition of [' + pv(this).inputO.id + ']: [' + v + ']'); return this; }, // input: (list, index), return [value, title[, key=title||value]] onList: function (l, i) { return [l[i] || i, Array.isArray(l) ? l[i] : i]; }, // input: (list, index), return value to set as input key onSelect: function (l, i) { return Array.isArray(l) ? l[i] : i; }, /* searchInList 的減縮版 _.searchInList.call(_instance_, 'includeKey'); eq _instance_.setSearch('includeKey'); */ setSearch: function (f) { return searchInList.call(this, f); }, setClassName: function (n) { var t = this; if (n) t.class_input = t.class_error = t.class_warning = n; else if (typeof n != 'undefined') { delete t.class_input; delete t.class_error; delete t.class_warning; } return setClassName.call(this, 'input', pv(this).inputO); }, setProperty: function (p, v) { var i = pv(this).inputO; library_namespace.debug('setProperty: ' + p + '=' + i[p] + '→' + v, 3); if (typeof v != 'undefined' && v != null) i[p] = v; return i[p]; }, // set/get input value setValue: function (v, caller) { if (arguments.length > 0) this.toggleToInput(); //library_namespace.log('setValue: ' + this.setProperty('value', v)); v = this.setProperty('value', v); //library_namespace.log('setValue: ' + v); if (arguments.length > 0 && caller !== do_verify) { //library_namespace.log('setValue: call do_verify(' + v + '), list: [' + this.allListCount + ']' + this.setAllList()); do_verify.call(this, v); } return v; }, // set inputted value: 轉換成輸入過的 <span> 時,設定其之值。 setInputted: function (v) { var _p = pv(this), i = _p.inputO; if (typeof v === 'undefined') v = this.dInputted(); // dInputted: default inputted value, ===setValue create_DO(0, removeAllChild(_p.inputtedO), v); return v; }, setMaxLength: function (l) { library_namespace.debug('setMaxLength: set length ' + (l > 0 ? l : null), 3); return this.setProperty('maxLength', l > 0 ? l : null); }, setName: function (n) { this.setProperty('id', n); return this.setProperty('name', n); }, setTitle: function (t) { if (t) pv(this).inputtedO.title = t; return this.setProperty('title', t || null); }, // 切換 inputted span/input toggleToInput: function () { return toggleToInput.apply(this, arguments); }, /* for Unobtrusive JavaScript: 為未啟用JavaScript的情況提供替代方案。 接上 <input> 或 <select> */ attach: function (o) { // (input or select object) library_namespace.debug('attach: ' + o, 4); //o.replaceNode(_p.inputO); o = layout.call(this, o); this.setAllList(this.setAllList()); return o; }, // (focus or blur, 不驅動 onfocus/onblur) focus: function (f) { // ,noE var i = pv(this).inputO; if (false) { sl('focus: ' + (f ? 'focus' : 'blur') + (noE ? ' and no event' : '')); if (f || typeof f === 'undefined') { if (noE) noE = i.onfocus, i.onfocus = null; i.focus(); //if(noE)i.onfocus = noE; } else { if (noE) noE = i.onblur, i.onblur = null; else this.showList(0); i.blur(); //if(noE)i.onblur = noE; } } if (f || typeof f === 'undefined') try { // @IE5-8 initial: Error @CeL: 2110 [Error] (facility code 10): 控制項不可見、未啟動或無法接受焦點,因此無法將焦點移到控制項上。 // Error @CeL: 2110 [Error] (facility code 10): Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus. i.focus(); } catch (e) { } else this.showList(0), i.blur(); }, // instance destructor --------------------------- /* // usage: instance = instance.destroy(); // or if you has something more to do: instance.destroy() && instance = null; */ destroy: function () { pv(this, 1); } }; // _.prototype= // =================================================== // prevent re-use. 防止再造 //delete _.clone; //_.allow_inherit = true; return ( _// JSDT:_module_ ); }