// Custom selectbox using prototype & scriptaculous
// require prototype 1.6
SelectBox = Class.create();
SelectBox.prototype = {
// selectbox id passed to replace by custom
id: 0,
// original selectbox element
original_selectbox : false,
// misc
selectText: "please select",
active_select: null,
_active: false,
all_selects: false,
//positions
options_top : 0,
options_left : 0,
select_width : 0,
// animation
animation_show : 'slide',
animation_show_interval : 0.0,
animation_hide : 'slide',
animation_hide_interval : 0.0,
// select area var
select_button_id_text: '',
select_button_class_text : '',
select_area_id_text: '',
select_area_class_text: '',
select_area_active_class_text: '',
select_text_id_text: '',
// functions on events
// options area var
option_id_text: '',
option_holder_id_text: '',
option_holder_visible_class_text: '',
option_holder_invisible_class_text: '',
//Added by greg for use by the afterManualHide function.
the_select_box: null,
// construct
initialize: function (params) {
// require id of selectbox
if (typeof params.id == 'undefined') {
alert('selectbox id in params required');
return false;
}
//coord data...
this.options_top = params.options_top ? params.options_top : 0;
this.options_left = params.options_left ? params.options_left : 0;
this.select_width = params.select_width ? params.select_width : 0;
//animation type ..
this.animation_show = params.animation_show ? params.animation_show : this.animation_show;
this.animation_hide = params.animation_hide ? params.animation_hide : this.animation_hide;
//animation interval ..
this.animation_show_interval = params.animation_show_interval ? params.animation_show_interval : this.animation_show_interval;
this.animation_hide_interval = params.animation_hide_interval ? params.animation_hide_interval : this.animation_hide_interval;
var id = this.id = params.id;
this.original_selectbox = $(id);
// select area
this.select_button_id_text = this.id + '-select-button';
this.select_button_class_text = 'custom-select-button';
this.select_area_id_text = this.id + '-select-area';
this.select_area_class_text = 'select-area';
this.select_area_active_class_text = 'select-area-active';
this.select_text_id_text = this.id + '-select-text';
// options area
this.option_id_text = this.id + '-option-';
this.option_holder_id_text = this.id + '-options-holder';
this.option_holder_visible_class_text = 'options-visible';
this.option_holder_invisible_class_text = 'options-invisible';
// init
this.createMarkup(id);
this.initSelectEvent(this.select_button_id_text);
this.initOptionsEvent($(id));
this.all_selects = true;
},
// init select event
initSelectEvent: function (button_id) {
var self = this;
$(button_id).observe('click', function (event) {
self.showOptions(event, self);
Event.stop(event);
});
},
// init option click events
initOptionsEvent: function (selectBox) {
var self = this;
var me = selectBox;
for (var w = 0; w < me.options.length; w++) {
if (me.options[w].title.indexOf("title") == -1) {
$(self.option_id_text + w).observe('click', function (event) {
self.showOptions(event, self);
self.selectMe(selectBox, this.id.replace(self.option_id_text, ''));
Event.stop(event);
});
}
}
},
// create dom element with for custom selectbox
createMarkup: function (id) {
var selectBox = $(id);
var q = id;
//create and build div structure
var selectArea = document.createElement("div");
var left = document.createElement("span");
left.className = "left";
selectArea.appendChild(left);
var disabled = document.createElement("span");
disabled.className = "disabled";
selectArea.appendChild(disabled);
selectBox._disabled = disabled;
var center = document.createElement("span");
var button = document.createElement("a");
var text = document.createTextNode(this.selectText);
center.id = this.select_text_id_text;
button.id = this.select_button_id_text;
var stWidth = selectBox.offsetWidth;
selectArea.style.width = this.select_width ? this.select_width + "px" : stWidth + "px";
button.href = "#";
button.className = this.select_button_class_text;
selectArea.className = this.select_area_class_text;
selectArea.className += " " + selectBox.className;
selectArea.id = this.select_area_id_text;
center.className = "center";
center.appendChild(text);
selectArea.appendChild(center);
selectArea.appendChild(button);
selectBox.className += " outtaHere";
selectBox.parentNode.insertBefore(selectArea, selectBox);
var optionsDiv = document.createElement("div");
var optionsListParent = document.createElement("div");
optionsListParent.className = "select-center";
var optionsList = document.createElement("ul");
optionsDiv.innerHTML += "
";
optionsListParent.appendChild(optionsList);
optionsDiv.appendChild(optionsListParent);
selectBox._options = optionsList;
optionsDiv.style.width = this.select_width ? this.select_width + "px" : stWidth + "px";
optionsDiv._parent = selectArea;
optionsDiv.className = this.option_holder_invisible_class_text;
optionsDiv.id = this.option_holder_id_text;
this.populateSelectOptions(selectBox);
optionsDiv.innerHTML += "";
var existingOptionsHolder = $(id + "-options-holder");
if (existingOptionsHolder != null) {
existingOptionsHolder.parentNode.removeChild(existingOptionsHolder);
}
selectArea.appendChild(optionsDiv);
selectBox.replaced = true;
selectBox.up(0).appendChild(selectArea);
},
//collecting select options
populateSelectOptions: function (selectBox) {
var me = selectBox;
me._options.innerHTML = "";
for (var w = 0; w < me.options.length; w++) {
if (me.options[w].title.indexOf("title") == -1) {
var optionHolder = document.createElement('li');
var optionLink = document.createElement('a');
var optionTxt;
if (me.options[w].title.indexOf('image') != -1) {
optionTxt = document.createElement('img');
optionSpan = document.createElement('span');
optionTxt.src = me.options[w].title;
optionSpan = document.createTextNode(me.options[w].text);
} else {
optionTxt = document.createTextNode(me.options[w].text);
}
optionLink.href = "#";
optionLink.id = this.option_id_text + w;
if (me.options[w].title.indexOf('image') != -1) {
optionLink.appendChild(optionTxt);
optionLink.appendChild(optionSpan);
} else {
optionLink.appendChild(optionTxt);
}
optionHolder.appendChild(optionLink);
me._options.appendChild(optionHolder);
if (me.options[w].selected) {
this.selectMe(selectBox, w);
}
}
else if (me.options[w].selected) this.selectMe(me.id, w);
}
if (me.disabled) {
me._disabled.style.display = "block";
} else {
me._disabled.style.display = "none";
}
},
// show options area
showOptions: function (event, selectbox) {
the_select_box = selectbox;
var self = selectbox;
var _selectHeight = self.options_top;
var id = self.id;
_elem = document.getElementById(self.option_holder_id_text);
var divArea = document.getElementById(self.select_area_id_text);
if (self.active_select && self.active_select != _elem) {
self.animateHide({
id : self.option_holder_id_text,
afterFinish: function () {
self.active_select.className = self.active_select.className.replace(self.option_holder_visible_class_text, self.option_holder_invisible_class_text);
//self.active_select.style.height = "auto";
self._active.className = self._active.className.replace(self.select_area_active_class_text, '');
}
});
}
if (_elem.className.indexOf(self.option_holder_invisible_class_text) != -1) {
_elem.style.left = "-9999px";
_elem.style.top = _selectHeight + 'px';
_elem.className = _elem.className.replace(self.option_holder_invisible_class_text, '');
_elem.className += " " + self.option_holder_visible_class_text;
$(_elem.id).setStyle({display:'none'});
_elem.style.left = self.options_left + 'px';
divArea.className += " " + self.select_area_active_class_text;
self._active = divArea;
self.active_select = _elem;
/*
if (document.documentElement) {
document.documentElement.onclick = function (e) {
self.hideSelectOptions(e, self)
};
} else {
window.onclick = self.hideSelectOptions;
}
*/
self.animateShow({
id : self.option_holder_id_text,
afterFinish: function () {
$(_elem.id).setStyle({display:'block'});
}
});
}
else if (_elem.className.indexOf(self.option_holder_visible_class_text) != -1) {
self.animateHide({
id : self.option_holder_id_text,
afterFinish: function () {
//_elem.style.height = "auto";
_elem.className = _elem.className.replace(self.option_holder_visible_class_text, '');
_elem.className += " " + self.option_holder_invisible_class_text;
divArea.className = divArea.className.replace(self.select_area_active_class_text, '');
}
});
}
},
animateHide: function (params) {
switch (this.animation_hide) {
case 'slide':
Effect.SlideUp(params.id, {
duration: this.animation_hide_interval,
afterFinish: params.afterFinish
});
break;
case 'fade':
Effect.Fade(params.id, {
duration: this.animation_hide_interval,
afterFinish:params.afterFinish
});
break;
case 'blind':
Effect.BlindUp(params.id, {
duration: this.animation_hide_interval,
afterFinish:params.afterFinish
});
break;
case 'shrink':
Effect.Shrink(params.id, {
duration: this.animation_hide_interval,
afterFinish:params.afterFinish
});
break;
case 'squish':
Effect.Squish(params.id, {
duration: this.animation_hide_interval,
afterFinish:params.afterFinish
});
break;
}
},
afterManualHide: function() {
//Added by Greg - Added a listener during initialization, which will hide the dropdown if anywhere on the site is clicked (before u had to click on the down arrow)
//Anyway, I needed to add this, else the arrow would need to be clicked twice to show the dropdown again.
try {
var self = the_select_box;
self.active_select.className = self.active_select.className.replace(self.option_holder_visible_class_text, self.option_holder_invisible_class_text);
//self.active_select.style.height = "auto";
self._active.className = self._active.className.replace(self.select_area_active_class_text, '');
} catch (err) {
}
},
animateShow: function (params) {
switch (this.animation_show) {
case 'slide':
Effect.SlideDown(params.id, {
duration: this.animation_show_interval,
afterFinish:params.afterFinish
});
break;
case 'appear':
Effect.Appear(params.id, {
duration: this.animation_show_interval,
afterFinish:params.afterFinish
});
break;
case 'blind':
Effect.BlindDown(params.id, {
duration: this.animation_show_interval,
afterFinish:params.afterFinish
});
break;
}
},
// select option
selectMe: function (selectField, linkNo) {
selectNo = selectField.id;
for (var k = 0; k < selectField.options.length; k++) {
if (k == linkNo) {
selectField.options[k].selected = true;
}
else {
selectField.options[k].selected = false;
}
}
textVar = document.getElementById(this.select_text_id_text);
var newText;
var optionSpan;
if (selectField.options[linkNo].title.indexOf('image') != -1) {
newText = document.createElement('img');
newText.src = selectField.options[linkNo].title;
optionSpan = document.createElement('span');
optionSpan = document.createTextNode(selectField.options[linkNo].text);
} else {
newText = document.createTextNode(selectField.options[linkNo].text);
}
if (selectField.options[linkNo].title.indexOf('image') != -1) {
if (textVar.childNodes.length > 1) textVar.removeChild(textVar.childNodes[0]);
textVar.replaceChild(newText, textVar.childNodes[0]);
textVar.appendChild(optionSpan);
} else {
if (textVar.childNodes.length > 1) textVar.removeChild(textVar.childNodes[0]);
textVar.replaceChild(newText, textVar.childNodes[0]);
}
if (selectField.onchange && this.all_selects) {
eval(selectField.onchange());
}
},
// find y position
findPosY: function (obj) {
var posTop = 0;
while (obj.offsetParent) {
posTop += obj.offsetTop;
obj = obj.offsetParent;
}
return posTop;
},
//find x position
findPosX: function (obj) {
var posLeft = 0;
while (obj.offsetParent) {
posLeft += obj.offsetLeft;
obj = obj.offsetParent;
}
return posLeft;
},
// hide option area
hideSelectOptions: function (e, self) {
if (self.active_select) {
if (!e) e = window.event;
var _target = (e.target || e.srcElement);
if (self.isElementBefore(_target, self.select_area_class_text) == 0 && self.isElementBefore(_target, self.option_holder_id_text) == 0) {
self.active_select.className = self.active_select.className.replace(self.option_holder_visible_class_text, '');
self.active_select.className = self.active_select.className.replace(self.option_holder_invisible_class_text, '');
self.active_select.className += " " + self.option_holder_invisible_class_text;
self._active.className = self._active.className.replace(self.select_area_active_class_text, '');
self.active_select = false;
if (document.documentElement) {
document.documentElement.onclick = function () {
};
}
else {
window.onclick = null;
}
}
}
},
// check if element
isElementBefore: function (_el, _class) {
var _parent = _el;
do {
_parent = _parent.parentNode;
}
while (_parent && _parent.className != null && _parent.className.indexOf(_class) == -1)
if (_parent.className && _parent.className.indexOf(_class) != -1) {
return 1;
} else {
return 0;
}
}
};
//Hack by Greg:
//When the options change in a select box, the custom box does not register them, as it has already generated.
//In order to do this, I had to manually nuke the generated elements, and then nuke and recreate the original selectbox..
function reloadCustomSelect(id, width, height, disabled) {
var customElm = $(id + '-select-area');
if (customElm!=null) {
try {
var customElm = $(id + '-select-area');
customElm.remove();
var selectBox = $(id);
var selectBoxParent = selectBox.parentNode;
selectBoxParent.removeChild(selectBox);
if (disabled==true) {
disabled = "disabled";
} else {
disabled = "";
}
//Hack to reset whatever binding the script had to the original element. We're just recreating it.
selectBoxParent.innerHTML = getOuterHtml(selectBox);
$(id).className="";
addCustomSelectBox(id, width, height, true);
} catch (err) {
console.log("Error reloading custom select" + err)
}
} else {
//Has not been iitialized before.
addCustomSelectBox(id, width, height, true);
}
}
function getOuterHtml(node) { //Gets the html of an element, including its tag. (as opposed to innerHTML)
var element = document.createElement("div");
element.appendChild(node);
var html = element.innerHTML;
return html;
}
//Added by Greg - This stores all instantiations of the custom select box - I don't think its being used any more, actually.
//var customSelectBox = new Array();
//Allows for a js call to style a select element, as opposed to scheme generation.
function initCustomSelectBox(id, width, displacement) {
// replace with custom selectbox
var customSelectBox = new SelectBox({
id:id, // * required
animation_show:'appear', // slide, appear, blind
animation_show_interval: 0.1, // 0.1 ... infinity
animation_hide:'slide', // slide, fade, blind
animation_hide_interval: 0.1, // 0.1 ... infinity
select_width: width, // new selectbox width
options_top: displacement, // options holder offset
options_left: 0 // options holder offset
});
$(id + '-select-button').style.left = width + 'px';
//Added by Greg - Hacking the original code, so that clicking anywhere on the page when the dropdown is open, will close it.
Event.observe(document, 'click', function() {
customSelectBox.animateHide({'id':id + '-options-holder',
afterFinish: function () {
//Does some cleanup, after manually hiding (didn't write this code, just refactored it)
customSelectBox.afterManualHide();
}
});
});
//customDropDowns.push(customSelectBox);
return customSelectBox;
}
//Allows for a js call to style a select element, as opposed to scheme generation.
function addCustomSelectBox(id, width, displacement, now) {
if (now != null && now) {
return initCustomSelectBox(id, width, displacement);
} else {
document.observe("dom:loaded", function() {
return initCustomSelectBox(id, width, displacement);
});
}
}