Provides the ability for select boxes of a certain style to become text boxes if the options offered are not good enough.
The following select is of class 'combo'. Onload this property is detected, and the switch button added dynamically.
Sorry, there is no switch back
When the switch is made, the underlying value of the options (if any) is exposed as text. It will be submitted as part of the form exactly the same as the select would have been.
/////////////////////////////////////////////////////////////////
/**
* @file combobox.js
*
* Support a DHTML combo box - allow either selectbox or freetext data entry in one field
*
* @author dan [at] coders.co.nz
*/
// The class ID used to ID which select boxes may become freetext also
var COMBO_CLASS = "combo";
/**
* Update all labelled combo boxes found in the page
*/
function init_combo_boxes() {
if (document.getElementsByTagName) {
var f = document.getElementsByTagName('select');
for (var i=0; f.length > i; i++) {
if ( hasClass(f[i],COMBO_CLASS) )
{
init_combo_box(f[i]);
}//if
}//for
}//if
}
/**
* Setup the given select box with a button that will change it to a text field instead.
* The button is created programatically after page load, so should not effect anything with
* noscript
*/
function init_combo_box(field) {
if(!field)return
var field_id = field.getAttribute('id')
if(! field_id ){
field_id = field.getAttribute('name');
field.setAttribute('id',field_id);
}
var container = field.parentNode;
var newButton = null;
// Look for a button already there, don't add if it's been done
var existing = container.getElementsByTagName("input");
for(var ix in existing){
if(existing[ix] && existing[ix].getAttribute){
if(existing[ix].getAttribute("type") == "button")
newButton=existing[ix];
}
}
if (! newButton ){
newButton = document.createElement("input");
newButton.setAttribute("type","button");
newButton.setAttribute("value","T");
newButton.setAttribute("title","TEXT: click here to enter a freetext URL or identifier");
newButton.setAttribute("id","combo_button_"+field_id);
var n=field.nextSibling;
if(n){
container.insertBefore(newButton,n);
} else {
container.appendChild(newButton);
}
}
// Do add the event each time, as DOM manipulation doesn't do that for us.
addEvent(newButton, 'click', switch_to_freetext);
}
function init_combo_box_named(field_id) {
var field = document.getElementById(field_id);
if(field){init_combo_box(field)};
}
/**
* Change the type of input from Select to Text.
* Called when the button is pressed. Actually discards the select
* (so you can't get it back) and makes a new field with the same name
*/
function switch_to_freetext(event) {
if(! (e = event.srcElement)){ e = event.target }
if(! e ) {return;}
var id = e.id.substring(13);
var element = document.getElementById(id);
if(element){
change_element_to_freetext(element)
} else {
alert("Failed to find element "+id)
}
}
function change_element_to_freetext(element) {
var newField = document.createElement("input");
newField.setAttribute("type","text");
newField.setAttribute("name", element.getAttribute("name"));
newField.setAttribute("size", 40);
if(element.options && (element.selectedIndex >= 0) ){
newField.setAttribute("value", element.options[element.selectedIndex].value);
}
else {
newField.setAttribute("value", element.getAttribute("value"));
}
newField.setAttribute("class", element.getAttribute("class"));
newField.setAttribute("className", element.getAttribute("className"));
var id = element.id;
element.parentNode.replaceChild(newField,element);
newField.id = id;
newField.style.width="95%";
/* -- causes more confusion than not? */
// Remove the text button
var existing = newField.parentNode.getElementsByTagName("input");
for(var ix in existing){
if(existing[ix] && existing[ix].getAttribute){
if(existing[ix].getAttribute("type") == "button"){
var TButton=existing[ix]
TButton.parentNode.removeChild(TButton);
}
}
}
}
addEvent(window, 'load', init_combo_boxes);
// Utils.
// credits: http://ejohn.org/projects/flexible-javascript-events/
function addEvent( obj, type, fn ) {
if(!obj){alert('no object passed to addEvent'); return;}
if ( obj.attachEvent ) {
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
} else {
obj.addEventListener( type, fn, false );
}
}
function removeEvent( obj, type, fn ) {
if(!obj){alert('no object passed to addEvent'); return;}
if ( obj.detachEvent ) {
obj.detachEvent( "on"+type, obj[type+fn] );
obj[type+fn] = null;
} else
obj.removeEventListener( type, fn, false );
}
/**
* Returns true if an element has a specified class name
*/
function hasClass(node, className) {
if (node.className == className) {
return true;
}
var reg = new RegExp('(^| )'+ className +'($| )')
if (reg.test(node.className)) {
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////
DOM by Dan