/** * Created by chamaeleon (chamaeleon-nitr[at]yandex.ru). * Date: 07.09.13 * Time: 22:55 */ var bindReady = function (handler) { var called = false, isFrame, fn; function ready() { if (called) { return; } called = true; handler(); } function tryScroll() { if (called) { return; } try { document.documentElement.doScroll("left"); ready(); } catch (e) { setTimeout(tryScroll, 10); } } if (document.addEventListener) { document.addEventListener("DOMContentLoaded", ready, false); } else if (document.attachEvent) {// IE try { isFrame = window.frameElement !== null; } catch (e) { } // IE, the document is not inside a frame if (document.documentElement.doScroll && !isFrame) { tryScroll(); } // IE, the document is inside a frame document.attachEvent("onreadystatechange", function () { if (document.readyState === "complete") { ready(); } }); } // Old browsers if (window.addEventListener) { window.addEventListener('load', ready, false); } else if (window.attachEvent) { window.attachEvent('onload', ready); } else { fn = window.onload; window.onload = function () { if (typeof fn === 'function') { fn(); } ready(); }; } }; var ComboBox = function (id_or_element) { var select = typeof id_or_element === 'string' ? document.getElementById(id_or_element) : id_or_element, divs = [], options, parent, combobox = document.createElement('div'), input = document.createElement('input'), list = document.createElement('div'), trigger = document.createElement('div'), targetSelect = null, selectElem = null, oldselectElem = null, currentIndex = 0, i, el, value, label, currentTarget, escapeExp = new RegExp("([" + ["[", "]", "{", "}", "(", ")", "+", "*", "\\", "?", ".", "$", "^"].join("\\") + "])", "g"); if (!select) { select = new Error('not found element "' + id_or_element + '"'); return; } id_or_element = typeof id_or_element === 'string' ? id_or_element : id_or_element.id; function setSize() { // size by select element if (select.offsetWidth > 0) { combobox.offsetWidth = select.offsetWidth; input.style.width = (select.offsetWidth - 34) + 'px'; } if (select.style.width !== '') { combobox.style.width = select.style.width; } if (select.style.height !== '') { combobox.style.height = select.style.height; } if (select.style.font !== '') { combobox.style.font = select.style.font; } if (combobox.offsetWidth > 0) { input.style.width = (combobox.offsetWidth - 34) + 'px'; } if (combobox.offsetHeight > 0) { list.style.top = combobox.offsetHeight + 'px'; } } // document DOM ready bindReady(setSize); // functions function hide(elem) { elem.style.display = 'none'; } function show(elem) { elem.style.display = 'block'; } function toggleList() { if (list.style.display && list.style.display === 'block') { hide(list); } else { show(list); } } function clearCls(classname) { var regexp = new RegExp('\\s*' + (classname || 'selected') + '\\s*', 'i'), i; for (i = 0; i < divs.length; i++) { divs[i].el.className = divs[i].el.className.replace(regexp, ''); } } function removeCls(el, cls) { var regexp = new RegExp('\\s*' + (cls || 'selected') + '\\s*', 'i'); el.className = el.className.replace(regexp, ''); } function addCls(el, cls) { if (el) { el.className = el.className + ' ' + cls; } } function selection(elem) { //this.className = !/selection/.test(this.className) ? this.className + ' selection' : this.className.replace(/\s*selection\s*/i, ''); if (elem) { //clearCls('selection'); if (targetSelect) { removeCls(targetSelect, 'selection'); } targetSelect = elem; addCls(elem, 'selection'); } } function optionSelect(elem) { var oldvalue = select.value; hide(list); if (elem) { // && elem !== selectElem input.value = elem.innerText; select.value = elem.value; if (typeof select.onchange === 'function' && (oldvalue !== elem.value)) { // && (elem.value && oldvalue !== elem.value) select.onchange(); } //clearCls(); if (selectElem) { removeCls(selectElem, 'selected'); } selectElem = elem; addCls(elem, 'selected'); } oldselectElem = selectElem; } function selectItem(el) { addCls(el, 'selected'); if (selectElem) { removeCls(selectElem, 'selected'); } selectElem = el; input.value = el.innerText; } function optionSelectEvent() { optionSelect(this); } function optionMouseOverEvent(index) { return function () { currentIndex = index; selection(this); }; } function filter() { var regexp = new RegExp('(' + input.value.replace(escapeExp, "\\$1") + ')', 'i'), i, elem; targetSelect = selectElem; clearCls('selection'); for (i = 0; i < divs.length; i++) { elem = divs[i].el; if (!regexp.test(divs[i].label)) { if (selectElem === elem) { removeCls(selectElem, 'selected'); selectElem = null; } hide(elem); if (targetSelect === elem) { removeCls(targetSelect, 'selection'); targetSelect = null; } } else { elem.innerHTML = elem.innerHTML.replace(/<(b|\/b)>/ig, ''); elem.innerHTML = elem.innerHTML.replace(regexp, '$1'); show(elem); if (!targetSelect) { currentIndex = i; selection(elem); } } } if (oldselectElem && regexp.test(oldselectElem.innerHTML) && !selectElem) { if (!selectElem) { selectElem = oldselectElem; } addCls(oldselectElem, 'selected'); } } function selectFirstItem() { var regexp = new RegExp(input.value.replace(escapeExp, "\\$1"), 'i'); if (targetSelect && (!selectElem || !selectElem.value)) { optionSelect(targetSelect); } else if (!selectElem && oldselectElem && regexp.test(oldselectElem.innerHTML)) { optionSelect(oldselectElem); } else { selectItem(selectElem); } } select.style.display = 'none'; combobox.setAttribute('id', 'cb_' + id_or_element); combobox.className = 'combobox'; list.className = 'cblist'; list.style.display = 'none'; input.className = 'cbinput'; input.setAttribute('type', 'text'); trigger.className = 'cbtrigger'; //trigger.innerHTML = '▼'; trigger.innerHTML = '▼'; // parent element of select parent = select.parentElement; // insert into DOM parent.insertBefore(combobox, select); combobox.insertBefore(list, null); combobox.insertBefore(trigger, null); combobox.insertBefore(input, list); options = select.getElementsByTagName('option'); for (i = 0; i < options.length; i++) { el = document.createElement('div'); value = options.item(i).value; label = options.item(i).text || value; el.setAttribute('value', value); el.value = value; el.innerText = label; el.onclick = optionSelectEvent; el.onmouseover = optionMouseOverEvent(i); divs.push({ label: label, value: value, el: el }); if (value === '' || !value) { selectItem(el); } if (options.item(i).selected && el !== selectElem) { selectItem(el); } list.insertBefore(el, null); } trigger.onclick = function () { if (selectElem && !selectElem.value) { input.value = ''; } input.select(); setTimeout(function () { toggleList(); }, 200); }; input.onclick = function () { if (selectElem && !selectElem.value) { input.value = ''; } input.select(); setTimeout(function () { toggleList(); }, 200); }; input.onblur = function () { setTimeout(function () { hide(list); selectFirstItem(); //optionSelect(selectElem); }, 200); }; input.onkeyup = function (e) { e = e || window.event; // enter if (e.keyCode === 13) { targetSelect = divs[currentIndex].el; optionSelect(targetSelect); e.cancelBubble = true; } else if (e.keyCode === 38 || e.keyCode === 40) { e.cancelBubble = true; } else { show(list); filter(); } }; input.onkeydown = function (e) { e = e || window.event; var elem; if (e.keyCode === 38) { // up elem = divs[currentIndex].el; removeCls(elem, 'selection'); currentIndex--; if (!divs[currentIndex]) { currentIndex = divs.length - 1; } targetSelect = divs[currentIndex].el; addCls(targetSelect, 'selection'); targetSelect.scrollIntoView(false); e.cancelBubble = true; if (navigator.appName !== 'Microsoft Internet Explorer') { //!/msie/i.test(navigator.userAgent.toLowerCase()) e.preventDefault(); e.stopPropagation(); } } else if (e.keyCode === 40) { // down elem = divs[currentIndex].el; removeCls(elem, 'selection'); currentIndex++; if (!divs[currentIndex]) { currentIndex = 0; } targetSelect = divs[currentIndex].el; addCls(targetSelect, 'selection'); targetSelect.scrollIntoView(false); e.cancelBubble = true; if (navigator.appName !== 'Microsoft Internet Explorer') { //!/msie/i.test(navigator.userAgent.toLowerCase()) e.preventDefault(); e.stopPropagation(); } } }; setSize(); }; /*function generateCombobox() { var selects = document.querySelectorAll('select[combobox="true"]'), i, el, cb; console.log(selects); for (i = 0; i < selects.length; i++) { el = selects[i]; if (el && !document.getElementById('cb_' + el.id)) { cb = new ComboBox(selects[i]); } } }*/