/**
* 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]);
}
}
}*/