Created
December 11, 2010 11:28
-
-
Save pacoguzman/737324 to your computer and use it in GitHub Desktop.
Transform select multiple to a single select - Progressive Enhancement
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Convert a multi-select into a single_select which keeps track of choices in an external list with | |
// hidden fields. The hidden fields have the same field name as the multi select. list_class | |
// defaults to the select id + "_data" Chosen options are moved from the 'Add' option group to | |
// the 'Remove' option group, Each suffixed by the given 'title' or the string "Option". The select | |
// header is extracted from the select's label for - if it exists. Otherwise it just prints 'Options...' | |
// | |
// Example: | |
// | |
// $("select_multi").multiSingleSelect({list_class:'select_multi_data', title:'Option', | |
// remove: "Remove", add: "Add", prompt: "Options..."}); | |
// | |
// Dependencies: prototype-1.7.0 | |
// insert(insertion) == insert({bottom:insertion}) | |
(function() { | |
var MultiSingle = { | |
selectRemove : function(elem_id, list_class, html, val) { | |
var element = $(elem_id); | |
var selected = element.down("optgroup.remove option[value='" + val + "']"); | |
if (selected) { | |
selected.writeAttribute('selected', false).removeClassName('removable'); | |
this.addOrdered(elem_id, val, selected); | |
} | |
element.next("ul." + list_class).select("li").each(function(li) { | |
if (li.down('span').innerHTML == html) { | |
li.remove(); | |
} | |
}); | |
element.next("span." + list_class).select("input").each(function(input) { | |
if (input.getValue() == val) { | |
input.remove(); | |
} | |
}); | |
}, | |
addOrdered : function(elem_id, val, selected) { | |
var add_group = $(elem_id).down("optgroup.add"); | |
var added_options = add_group.select("option"); | |
if (added_options.length > 0) { | |
var selected_position = selected.retrieve("position"); | |
var option_detected = added_options.detect(function(option) { | |
return option.retrieve("position") > selected_position; | |
}); | |
if (option_detected) { | |
return option_detected.insert({before: selected}); | |
} | |
} | |
add_group.insert(selected); | |
}, | |
selectAdd : function(element, selected, list_class) { | |
element = $(element); | |
var html = selected.innerHTML; | |
var val = selected.readAttribute("value"); | |
var li = new Element('li').store('html', html).store('val', val).insert("<span>" + html + "</span><a href\"\">x</a>"); | |
element.next("ul." + list_class).insert(li); | |
element.next("span." + list_class).insert(new Element('input', {type: 'hidden', name: element.retrieve("name"), value: val})); | |
} | |
}; | |
Element.addMethods('SELECT', { | |
multiSingleSelect: function(element, options) { | |
element = $(element); | |
var elem_id = element.readAttribute("id"); | |
var settings = Object.extend({ | |
list_class: elem_id + "_data", | |
title: "Option", | |
add: "Add", | |
remove: "Remove" | |
}, options || {}); | |
if (!settings.prompt) { | |
var elem_label = $$("label[for=" + elem_id + "]"); | |
if (elem_label.size() > 0) { | |
settings.prompt = elem_label.first().innerHTML + "..."; | |
} else { | |
settings.prompt = settings.title + "s" + "..."; | |
} | |
} | |
// Grab the name of the select and store, and give that name to all hidden fields | |
var elem_name = element.readAttribute('name'); | |
element.store('name', elem_name).writeAttribute('name', false); | |
var add_group = new Element("optgroup", {'class': 'add', label: settings.add + ' ' + settings.title}); | |
var remove_group = new Element("optgroup", {'class': 'remove', label: settings.remove + ' ' + settings.title}); | |
element.insert(add_group); | |
element.insert(remove_group); | |
element.insert({after: new Element("ul", {'class': settings.list_class})}); | |
element.insert({after: new Element("span", {'class': settings.list_class})}); | |
var selectedAdd = function($elem, $selected) { | |
$selected.writeAttribute('selected', false).addClassName('removable'); | |
remove_group.insert($selected); | |
MultiSingle.selectAdd($elem, $selected, settings.list_class); | |
}; | |
// remove each selected and push to end | |
element.select('option').each(function(selected, i) { | |
selected.store("position", i + 1); | |
if (!selected.readAttribute('selected')) { | |
add_group.insert(selected); | |
} else { | |
selectedAdd(element, selected); | |
} | |
}); | |
element.insert({top: new Element("option", {'class': 'directive', value: '0'}).update(settings.prompt)}); | |
element.observe('change', function(event) { | |
var selected = $(this).down(":selected"); | |
if (!selected || selected.readAttribute('value') == "0") return; | |
if (selected.hasClassName('removable')) { | |
MultiSingle.selectRemove(elem_id, settings.list_class, | |
selected.innerHTML, selected.readAttribute('value')); | |
} else { | |
selectedAdd(this, selected); | |
} | |
this.selectedIndex = 0; | |
}); | |
document.on('click', 'ul.' + settings.list_class + " a", function(event, link) { | |
event.preventDefault(); | |
var li = link.up("li"); | |
MultiSingle.selectRemove(elem_id, settings.list_class, li.retrieve('html'), li.retrieve('val')); | |
}); | |
return element.writeAttribute('multiple', false).writeAttribute('size', false); | |
} | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment