You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

163 lines
4.2 KiB

/*
jquery-selectunique.js v0.1.0
Given a group of select fields with the same options, SelectUnique will remove an option from the
other select fields when it's selected, and put it back when it's changed.
Home: http://github.com/sshaw/jquery-selectunique
License (MIT): http://www.opensource.org/licenses/mit-license.php
Copyright (c) 2013 Skye Shaw
*/
(function($) {
var NS = 'selectunique';
var KEY_SELECTED = NS + '-selected';
var SelectUnique = function(q, options) {
var self = this;
self.q = q.find('option').parent('select'); // We need a set containing the select elements
self.options = $.extend({}, options);
self.optionIndex = {};
self.q.on('change.' + NS, function() {
self._selectChanged($(this));
});
$(self._uniqueOptions(self.q.find('option'))).each(function() {
self.optionIndex[self._optionId(this)] = this.index;
});
self.q.has(':selected').each(function() {
self._optionSelected($(this));
});
};
SelectUnique.prototype = {
constructor: SelectUnique,
_selectChanged: function(select) {
var self = this, prevOption = select.data(KEY_SELECTED);
if(prevOption) {
self.q.not(select).each(function() {
var thisSelect = $(this);
thisSelect.append(self._cloneOption(prevOption));
self._sortOptions(thisSelect);
});
}
self._optionSelected(select);
},
_optionSelected: function(select) {
var self = this, selOption = select.find(':selected');
if(self._ignoreOption(selOption)) {
select.data(KEY_SELECTED, null);
}
else {
select.data(KEY_SELECTED, selOption);
self.q.not(select).each(function() {
var thisSelect = $(this);
thisSelect.find('option').each(function() {
var thisOption = $(this);
// Ignore val(), we only care about what the user sees. This allows for cases
// where the text is the same but the value is dependent on the select it's in.
if(selOption.text() == thisOption.text()) {
thisOption.remove();
return;
}
});
});
}
},
_ignoreOption: function(option) {
return $.trim(option.val()) == '' || ($.isFunction(this.options.ignoreOption) && this.options.ignoreOption(option));
},
_cloneOption: function(option) {
// We must set selected to false everytime because this will be true:
// (cache[x] = original.clone(true).prop('selected', false)).clone(true).prop('selected')
return option.clone(true).prop('selected', false);
},
_sortOptions: function(select) {
var self = this, options = select.find('option'), val = select.val();
options.sort(function(a,b) {
return self.optionIndex[self._optionId(a)] - self.optionIndex[self._optionId(b)];
});
select.html(options);
select.val(val);
},
_optionId: function(option) {
return [option.value, option.text].join('-');
},
_uniqueOptions: function(options) {
var self = this, unique = [], seen = {};
options.each(function() {
var key = self._optionId(this);
if(!seen[key] && !self._ignoreOption($(this))) {
seen[key] = true;
unique.push(this);
}
});
return unique;
},
_removeHandlers: function() {
this.q.off('.'+NS);
},
refresh: function() {
var self = this;
},
selected: function() {
var selected = this._uniqueOptions(this.q.find(':selected'));
return $.map(selected, function(e) {
return e.cloneNode(true);
});
},
remaining: function() {
var remaining = this._uniqueOptions(this.q.find('option:not(:selected)'));
return $.map(remaining, function(e) {
return e.cloneNode(true);
});
}
};
$.fn.selectunique = function(options) {
if(this.has('select,option').length) {
var uniq = this.data(NS);
if(!uniq)
this.data(NS, uniq = new SelectUnique(this, options));
if(typeof options == 'string') {
if(options == 'refresh') {
uniq._removeHandlers();
this.data(NS, uniq = new SelectUnique(this));
}
else {
if(!uniq[options])
$.error("selectunique: no such method '" + options + "'");
return uniq[options]();
}
}
}
return this;
};
})(window.jQuery);