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
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);
|