Created
May 28, 2010 20:17
-
-
Save mkkeck/417672 to your computer and use it in GitHub Desktop.
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
/** | |
* jQuery UI Multiselect Advanced | |
* | |
* Replaces the jQuery UI Multiselect from the page | |
* <http://www.quasipartikel.at/multiselect/> | |
* | |
* | |
* Author: Michael Keck | |
* | |
* Based on the original code from: | |
* <http://www.quasipartikel.at/multiselect/> | |
* written by | |
* - Michael Aufreiter (quasipartikel.at) | |
* - Yanick Rochon (yanick.rochon[at]gmail[dot]com) | |
* (c) Copyright: Michael Aufreiter and Yanick Rochon | |
* | |
* | |
* (c) Copyright: 2010, Michael Keck | |
* <http://www.michaelkeck.de/projects/jquery> | |
* | |
* | |
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) | |
* licenses. | |
* | |
* | |
* Depends: ui.core.js | |
* ui.sortable.js | |
* ui.resizable.js (optional, but if you set the option | |
* 'resizable' to an value != false or '' | |
* you'll need this!) | |
* | |
* Usage: // INIT | |
* $('.selector').multiselect( | |
* // { your needed init options } | |
* ); | |
* // UPDATE | |
* $('.selector').multiselect({ | |
* 'optionname' : mixed option value | |
* }); | |
* | |
* Documentation: NONE (at the moment) | |
*/ | |
(function($) { | |
$.widget('ui.multiselect', { | |
// ------------------------------------------------------------------- | |
// OPTIONS | |
// ------------------------------------------------------------------- | |
options: { | |
// Icons | |
icons: { | |
removeItem: 'ui-icon-minus', // required | |
selectItem: 'ui-icon-plus', // required | |
selectAll: 'ui-icon-arrowthick-1-e', // optional (false to disable) | |
removeAll: 'ui-icon-arrowthick-1-w' // optional (false to disable) | |
}, | |
// Layout | |
cssclass: '', // optional className | |
height: 'auto', // height, if 'auto': orginal elements height used | |
width: 'auto', // width, if 'auto': orginal elements width used | |
// Resizable | |
resizable: 'e,s,se', // set to false for disabling | |
// Searching | |
search: { | |
enabled: true, // true enable search, fals disables search | |
input: 'input' // input or select, if select you've to pass | |
// a complete select box with all required | |
// options | |
}, | |
// Options to be added, removed or changed | |
data: { | |
empty: false, // Removes all options from multiselect | |
// Changes the select status of some options | |
// Supported selectors: *, $, !, ^ | | |
// See also <http://api.jquery.com/category/selectors/> | |
change: [ | |
// Examples: | |
// as an object (best way): | |
// { value : 'your val 1', selected : true }, | |
// { value : 'your val 2', selected : false }, | |
// { value : '*your', selected : false }, | |
// ... | |
// as an array (quick and dirty for only to revert the status): | |
// 'your val 1', 'your val 2', ... | |
], | |
// Adds some new options to the multiselect | |
insert: [ | |
// Examples: | |
// as an object (best way): | |
// { value : 'your val 1', option: 'text to display 1', selected : true }, | |
// { value : 'your val 2', option: 'text to display 2', selected : false }, | |
// ... | |
// as an array (quick and dirty): | |
// ['your val 1', 'text to display 1', true], | |
// ['your val 2', 'text to display 2', false], | |
// ... | |
], | |
// Removes some options from the multiselect | |
// Supported selectors: *, $, !, ^ | | |
// See also <http://api.jquery.com/category/selectors/> | |
remove: [ | |
// Examples: | |
// as an object (best way): | |
// { selected : true } // removes all selected | |
// { selected : false }, // removes all none selected | |
// { value : 'your val 1' }, // removes option with value | |
// { value : '*your' }, // removes option with value | |
// ... | |
// as an array (quick and dirty and only values are supported): | |
// 'your val 1', 'your val 2', ... | |
] | |
}, | |
// Animation | |
// Note: the effects you can use for 'show' and 'hide' are listed | |
// at <http://jqueryui.com/demos/effect/> | |
animate: { | |
hide: 'drop', // see <http://jqueryui.com/demos/hide/> | |
show: 'slide', // see <http://jqueryui.com/demos/show/> | |
speed: 'fast', // set to 0 or false, 'fast', 'slow' or a int | |
}, | |
// Callbacks | |
nodeComparator: function(n1, n2) { | |
var t1 = n1.text(), t2 = n2.text(); | |
return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1); | |
} | |
}, | |
// ------------------------------------------------------------------- | |
// PRIVATE FUNCTIONS | |
// ------------------------------------------------------------------- | |
// Clones a DOMElement and returns it's clone | |
// @param object node DOMElement | |
// @return object clone DOMElement cloned | |
_copynode: function(node) { | |
var clone = node.clone(); | |
clone.data('optionLink', node.data('optionLink')); | |
clone.data('idx', node.data('idx')); | |
return clone; | |
}, | |
// Updates the Counter Message | |
_updcount: function() { | |
this.countInfo.text( | |
this.lang.countItems.replace(/{count}/, this.count) | |
); | |
}, | |
// Set busy state | |
// @param boolean state true|false | |
_busy: function(state) { | |
if (state) { | |
this.countInfo.hide(); this.busyInfo.show(); | |
} | |
else { | |
this.busyInfo.hide(); this.countInfo.show(); | |
this._updcount(); | |
} | |
}, | |
// Filters available options | |
// @param object list DOMElement | |
_filter: function(list) { | |
var input = $(this), rows = list.children('li'), | |
cache = rows.map(function() { | |
return $(this).text().toLowerCase(); | |
}), | |
term = $.trim(input.val().toLowerCase()), | |
scores = []; | |
if (!term) { | |
rows.show(); | |
} | |
else { | |
rows.hide(); | |
cache.each(function(i) { | |
if (this.indexOf(term)>-1) { | |
scores.push(i); | |
} | |
}); | |
$.each(scores, function() { | |
$(rows[this]).show(); | |
}); | |
} | |
}, | |
// Get an DOMElement from an option | |
// @param object option DOMElement | |
// @return object li DOMElement | |
_getnode: function(option) { | |
var node = $('<li class="ui-element ui-state-default" title="' + $(option).text() + '">' + $(option).text() + '<a href="#" class="action ui-icon"> </a></li>').hide(); | |
node.data('optionLink', $(option)); | |
return node; | |
}, | |
// Get the serach string for finding options with a special | |
// selectors: *, $, !, ^ | | |
// See also <http://api.jquery.com/category/selectors/> | |
// @param string value | |
// @return string jQuery selector string | |
_findvalue: function(value) { | |
var pre = value.substring(0, 1), returnVal = ''; | |
if (pre !== '*' && pre !== '$' && pre !== '!' && pre !== '^' && pre != '|') { | |
returnVal = 'value="' + value + '"' | |
} else { | |
returnVal = 'value' + pre + '="' + value.substring(1, value.length) + '"'; | |
} | |
return returnVal; | |
}, | |
_initlists: function(data) { | |
var inp = this.element, | |
len = 0, num = 0, key = '', u = 'undefined', tmp; | |
// Remove all options from the multiselect | |
if (data.empty) { | |
inp.find('option').remove(); | |
} | |
// Remove some options with given values from the multiselect | |
else if (typeof(data.remove) !== u && data.remove.length > 0) { | |
tmp = data.remove; | |
len = data.remove.length; | |
for (num = 0; num < len; num++) { | |
// Quick and dirty: only support values | |
if (typeof(tmp[num]) !== 'object') { | |
inp.find('option[' + this._findvalue(tmp[num]) + ']').remove(); | |
} | |
// Default behaviour | |
else { | |
if (typeof(tmp[num]['selected']) !== u) { | |
if (tmp[num]['selected']) { | |
inp.find('option:selected').remove(); | |
} else { | |
inp.find('option:not(:selected)').remove(); | |
} | |
} else if (typeof(tmp[num]['value']) !== u) { | |
if (tmp[num]['value']) { | |
inp.find('option[' + this._findvalue(tmp[num]['value']) + ']').remove(); | |
} | |
} | |
} | |
} | |
} | |
// Insert new options to the multiselect | |
if (typeof(data.insert) !== u && data.insert.length > 0) { | |
tmp = data.insert; | |
len = data.insert.length; | |
for (num = 0; num < len; num++) { | |
// Very quick and dirty: only support values | |
if (typeof(tmp[num]) !== 'object') { | |
$('<option value="' + tmp[num] + '">' + tmp[num] + '</option>').appendTo(inp); | |
} | |
// Default behaviour | |
else { | |
var txt = '', val = '', sel = ''; | |
if (typeof(tmp[num]['value']) !== u) { | |
val = tmp[num]['value']; | |
} else if (typeof(tmp[num][0]) !== u) { | |
val = tmp[num][0]; | |
txt = tmp[num][0]; | |
} | |
if (typeof(tmp[num]['option']) !== u) { | |
text = tmp[num]['option']; | |
} else if (typeof(tmp[num][1]) !== u) { | |
if (tmp[num][1]) { | |
txt = tmp[num][1]; | |
} | |
} | |
if (typeof(tmp[num]['selected']) !== u) { | |
if (tmp[num]['selected']) { | |
sel = ' selected="selected"'; | |
} | |
} else if (typeof(tmp[num][2]) !== u) { | |
if (tmp[num][2]) { | |
sel = ' selected="selected"'; | |
} | |
} | |
if (val !== '') { | |
$('<option value="' + val + '"' + sel + '>' + ((txt !== '') ? txt : val) + '</option>').appendTo(inp); | |
} | |
} | |
} | |
} | |
// Change the selected state from options in multiselect | |
if (typeof(data.change) !== u && data.change.length > 0) { | |
tmp = data.change; | |
len = data.change.length; | |
for (num = 0; num < len; num++) { | |
sel = false; val = ''; | |
// Quick and dirty: only support values | |
if (typeof(tmp[num]) !== 'object') { | |
val = this._findvalue(tmp[num]); | |
sel = inp.find('option[' + val + ']').attr('selected'); | |
if (sel) { | |
inp.find('option[' + val + ']').removeAttr('selected'); | |
} else { | |
inp.find('option[' + val + ']').attr('selected', 'selected'); | |
} | |
} | |
// Default behaviour | |
else { | |
if (typeof(tmp[num]['selected']) !== u) { | |
sel = tmp[num]['selected']; | |
} | |
if (typeof(tmp[num]['value']) !== u) { | |
val = this._findvalue(tmp[num]['value']); | |
} | |
if (val !== '') { | |
if (sel) { | |
inp.find('option[' + val + ']').attr('selected', 'selected'); | |
} else { | |
inp.find('option[' + val + ']').removeAttr('selected'); | |
} | |
} | |
} | |
} | |
} | |
}, | |
// Gets all options elements from a multiselect list | |
// @param object options DOMElement(s) | |
// @return object item DOMElement | |
_makelists: function(options) { | |
this._busy(true); | |
this.availItems.children('.ui-element').remove(); | |
this.selectItems.children('.ui-element').remove(); | |
this.count = 0; | |
var self = this; | |
var items = $(options.map(function(i) { | |
var item = self._getnode(this); | |
item.appendTo(this.selected ? self.selectItems : self.availItems).show(); | |
if (this.selected) { | |
self.count += 1; | |
} | |
self._setstate(item, this.selected); | |
item.data('idx', i); | |
return item[0]; | |
})); | |
this._busy(false); | |
}, | |
// Register onHover Events | |
// @param DOMElement | |
_reghover: function(el) { | |
el.mouseover(function() { | |
$(this).removeClass('ui-state-default').addClass('ui-state-hover'); | |
}); | |
el.mouseout(function() { | |
$(this).removeClass('ui-state-hover').addClass('ui-state-default'); | |
}); | |
}, | |
// Register onRemove Events | |
// @param DOMElement | |
_regremove: function(el) { | |
var self = this; | |
// Single click on Icon | |
el.click(function() { | |
self._updoption($(this).parent(), false); | |
self.count -= 1; | |
self._updcount(); | |
return false; | |
}); | |
// Double click the parent DOMElement | |
el.parent().dblclick(function() { | |
self._updoption($(this), false); | |
self.count -= 1; | |
self._updcount(); | |
return false; | |
}); | |
}, | |
// Register onSearch Events | |
// @param DOMElement | |
// @param string type ('input' | 'select') | |
_regsearch: function(input, type) { | |
var self = this; | |
input.focus(function() { | |
$(this).addClass('ui-state-active'); | |
}).blur(function() { | |
$(this).removeClass('ui-state-active'); | |
}); | |
if (type !== 'select') { | |
input.keypress(function(e) { | |
if (e.keyCode == 13) { | |
return false; | |
} | |
}).keyup(function() { | |
self._filter.apply(this, [self.availItems]); | |
}); | |
} | |
else { | |
input.change(function() { | |
self._filter.apply(this, [self.availItems]); | |
return false; | |
}); | |
} | |
}, | |
// Register onSelect Events | |
// @param DOMElement | |
_regselect: function(el) { | |
var self = this; | |
// Single click on Icon | |
el.click(function() { | |
var item = self._updoption($(this).parent(), true); | |
self.count += 1; | |
self._updcount(); | |
return false; | |
}); | |
// Double click the parent DOMElement | |
el.parent().dblclick(function() { | |
self._updoption($(this), true); | |
self.count -= 1; | |
self._updcount(); | |
return false; | |
}); | |
}, | |
// Resizes the Multiselect Widget | |
_resize: function() { | |
var d = 0, s = this.sizes, p = this.options, v = 0; | |
// Calculate the Heights | |
if (s.bodyHeight > 0) { | |
this.container.height(s.bodyHeight); | |
d = this.container.height(); | |
if (d > 0) { | |
v = d - this.availHead.outerHeight(true); | |
this.availBody.height(d); this.availList.height(v); | |
this.availItems.height(v - 2); | |
this.selectBody.height(d); this.selectList.height(v); | |
this.selectItems.height(v - 2); | |
} | |
} | |
// Caclulate the Widths | |
if (s.bodyWidth > 0) { | |
this.container.width(s.bodyWidth); | |
v = Math.floor(this.container.width() * 0.5); | |
if (v > 0) { | |
this.availBody.width(v); this.selectBody.width(v); | |
if (p.search.enabled) { | |
d = ((this.availText.outerWidth(true) - this.availText.width()) * 2) + this.availText.find('.ui-icon').outerWidth(true) + (p.icons.selectAll ? this.selectAllIcon.outerWidth(true) : 0) + 5; | |
this.searchInput.width(v - d); | |
} | |
d = ((this.selectText.outerWidth(true) - this.selectText.width()) * 2) + (p.icons.removeAll ? this.removeAllIcon.outerWidth(true) : 0); | |
this.selectText.width(v - d).css({ 'overflow' : 'hidden' }); | |
this.selectText.find('panel-text').width(v - (d + this.selectText.find('.ui-icon').outerWidth(true))); | |
} | |
} | |
}, | |
// Sets the state of an element | |
// @param DOMElement | |
// @param bool state (true | false) set selected status | |
_setstate: function(item, state) { | |
// SELECTED | |
if (state) { | |
item.find('a.action').addClass(this.options.icons.removeItem).removeClass(this.options.icons.selectItem).attr('title', this.lang.removeItem).text(this.lang.removeItem); | |
// Register Remove Event | |
this._regremove(item.find('a.action')); | |
} | |
// NOT SELECTED | |
else { | |
item.find('a.action').addClass(this.options.icons.selectItem).removeClass(this.options.icons.removeItem).attr('title', this.lang.selectItem).text(this.lang.selectItem); | |
// Register Select Event | |
this._regselect(item.find('a.action')); | |
} | |
// Register Hover Event | |
this._reghover(item); | |
}, | |
// Sets the state of an element | |
// @param DOMElement | |
// @param bool state (true | false) set selected status | |
// @param bool noeffect (true | false) optional and only needed by | |
// drag and drop | |
_updoption: function(item, state, noeffect) { | |
var anim = this.options.animate; | |
item.data('optionLink').attr('selected', state); | |
// SELECTED | |
if (state) { | |
// look for successor based on initial option index | |
var items = this.selectItems.find('li'), comparator = this.options.nodeComparator; | |
var succ = null, i = item.data('idx'), d = comparator(item, $(items[i])); | |
// TODO: test needed for dynamic list populating | |
if (d) { | |
var l = items.length; | |
while (i > -1 && i < l) { | |
d > 0 ? i++ : i--; | |
if (d != comparator(item, $(items[i]))) { | |
// going up, go back one item down, otherwise leave as is | |
succ = items[d > 0 ? i : i+1]; | |
break; | |
} | |
} | |
} else { | |
succ = items[i]; | |
} | |
var other = this._copynode(item); | |
succ ? other.insertBefore($(succ)) : other.appendTo(this.selectItems); | |
// Effect? | |
if (!noeffect) { | |
if (anim.hide !== 'hide') { | |
$(item).hide(anim.hide, null, anim.speed, function() { $(this).remove(); }); | |
} else { | |
$(item).hide(anim.speed, function() { $(this).remove(); }); | |
} | |
} else { | |
$(item).hide().remove(); | |
} | |
other.appendTo(this.selectItems).hide(); | |
// Effect? | |
if (!noeffect) { | |
if (anim.show !== 'show') { | |
$(other).show(anim.show, null, anim.speed); | |
} else { | |
$(other).show(anim.speed); | |
} | |
} else { | |
$(other).show(); | |
} | |
this._setstate(other, true); | |
return other; | |
} | |
// NOT SELECTED | |
else { | |
// look for successor based on initial option index | |
var items = this.availItems.find('li'), comparator = this.options.nodeComparator; | |
var succ = null, i = item.data('idx'), d = comparator(item, $(items[i])); | |
// TODO: test needed for dynamic list populating | |
if (d) { | |
var l = items.length; | |
while (i > -1 && i < l) { | |
d > 0 ? i++ : i--; | |
if (d != comparator(item, $(items[i]))) { | |
// going up, go back one item down, otherwise leave as is | |
succ = items[d > 0 ? i : i+1]; | |
break; | |
} | |
} | |
} else { | |
succ = items[i]; | |
} | |
var other = this._copynode(item); | |
succ ? other.insertBefore($(succ)) : other.appendTo(this.availItems); | |
// Effect? | |
if (!noeffect) { | |
if (anim.hide !== 'hide') { | |
$(item).hide(anim.hide, null, anim.speed, function() { $(this).remove(); }); | |
} else { | |
$(item).hide(anim.speed, function() { $(this).remove(); }); | |
} | |
} else { | |
$(item).hide().remove(); | |
} | |
other.hide(); | |
// Effect? | |
if (!noeffect) { | |
if (anim.show !== 'show') { | |
$(other).show(anim.show, null, anim.speed); | |
} else { | |
$(other).show(anim.speed); | |
} | |
} else { | |
$(other).show(); | |
} | |
this._setstate(other, false); | |
return other; | |
} | |
}, | |
// ------------------------------------------------------------------- | |
// PUBLIC FUNCTIONS | |
// ------------------------------------------------------------------- | |
// UI Function | |
// Creates the Multiselect Widget | |
_create: function() { | |
var p = this.options, l = (this.lang = $.ui.multiselect.locale), u = 'undefined', evopts = {}; | |
// Check Animation Options | |
if ( !(typeof(p.animate) !== u && typeof(p.animate.speed) !== u && p.animate.speed) ) { | |
p.animate.speed = (this.options.animate.speed = 0); | |
p.animate.show = (this.options.animate.show = 'show'); | |
p.animate.hide = (this.options.animate.hide = 'hide'); | |
} | |
// Check Icons Options | |
if ( !(typeof(p.icons) !== u && typeof(p.icons.removeItem) !== u && p.icons.removeItem) ) { | |
p.icons.removeItem = (this.options.icons.removeItem = 'ui-icon-minus'); | |
} | |
if ( !(typeof(p.icons) !== u && typeof(p.icons.selectItem) !== u && p.icons.selectItem) ) { | |
p.icons.selectItem = (this.options.icons.selectItem = 'ui-icon-plus'); | |
} | |
// Busy state | |
this.busy = false; | |
// Overwrite Sortable and Droppable Options (deprecated) | |
this.options.sort = true; | |
this.options.drop = true; | |
// Populate Lists if given | |
if (this.options.data) { | |
var d = this.options.data; | |
if ( d.empty || (d.change && d.change.length > 0) || (d.insert && d.insert.length > 0) || (d.remove && d.remove.length > 0) ) { | |
this._initlists(this.options.data); | |
} | |
} | |
// Hide original object | |
this.id = this.element.attr('id'); | |
this.element.hide(); | |
// Main-Body Object | |
this.container = $('<div class="ui-multiselect ui-helper-clearfix ui-widget ui-corner-all' + (p.cssclass ? ' ' + p.cssclass : '') + '"></div>').insertAfter(this.element); | |
// Available Objects | |
this.availBody = $('<div class="ui-multiselect-left"></div>').appendTo(this.container); | |
this.availHead = $('<div class="ui-widget-header"></div>').appendTo(this.availBody); | |
this.availText = $('<div class="panel"></div>').appendTo(this.availHead); | |
this.availList = $('<div class="ui-widget-content"></div>').appendTo(this.availBody); | |
this.availItems = $('<ul class="available connected-list"><li class="ui-helper-hidden-accessible"> </li></ul>').css({ 'overflow' : 'auto','overflowX' : 'hidden' }).bind('selectstart', function() { return false; }).appendTo(this.availList); | |
// Selected Objects | |
this.selectBody = $('<div class="ui-multiselect-right"></div>').appendTo(this.container); | |
this.selectHead = $('<div class="ui-widget-header"></div>').appendTo(this.selectBody); | |
this.selectText = $('<div class="panel"></div>').css({ 'overflow' : 'hidden' }).appendTo(this.selectHead); | |
this.selectList = $('<div class="ui-widget-content"></div>').appendTo(this.selectBody); | |
this.selectItems = $('<ul class="selected connected-list"><li class="ui-helper-hidden-accessible"> </li></ul>').css({ 'overflow': 'auto', 'overflowX': 'hidden' }).bind('selectstart', function(){ return false; }).appendTo(this.selectList); | |
// Button 'Remove All' | |
this.removeAllIcon = $('<a href="#" class="ui-icon" title="' + l.removeAll + '">' + l.removeAll + '</a>').appendTo(this.selectHead).hide(); | |
// Button 'Select All' | |
this.selectAllIcon = $('<a href="#" class="ui-icon" title="' + l.selectAll + '">' + l.selectAll + '</a>').appendTo(this.availHead).hide(); | |
// Add Search Input for Live Search | |
this.searchType = false; | |
if (typeof(p.search) !== u && typeof(p.search.input) !== u) { | |
if (('' + p.search.input).substring(0, 6) == '<input' || ('' + p.search.input).substring(0, 7) == '<select') { | |
if (('' + p.search.input).substring(0, 7) == '<select') { | |
this.searchType = 'select'; | |
} else { | |
this.searchType = 'input'; | |
} | |
this.searchInput = $(p.search.input).appendTo(this.availText).hide(); | |
} | |
} | |
if (!this.searchType) { | |
this.searchInput = $('<input type="text" size="20" value="" />').appendTo(this.availText).hide(); | |
this.searchType = 'input'; | |
} | |
// Busy DOMElement | |
this.busyInfo = $('<div class="busy-info"><span class="ui-icon ui-icon-loading"></span><span class="panel-text">' + l.busy + '</span></div>').appendTo(this.selectText).show(); | |
// Count DOMElement | |
this.countInfo = $('<div class="count-info"><span class="panel-text"></span></div>').appendTo(this.selectText).hide(); | |
// init lists | |
var self = this; | |
this._busy(true); | |
this._makelists(this.element.find('option')); | |
// Add Event to 'Remove All' | |
if (p.icons.removeAll) { | |
this.removeAllIcon.addClass(p.icons.removeAll).show().click(function() { | |
self._makelists(self.element.find('option').removeAttr('selected')); | |
return false; | |
}); | |
} | |
// Add Event to 'Select All' | |
if (p.icons.selectAll) { | |
this.selectAllIcon.addClass(p.icons.selectAll).show().click(function() { | |
self._makelists(self.element.find('option').attr('selected', 'selected')); | |
return false; | |
}); | |
} | |
// Add Event to Search | |
if (p.search.enabled) { | |
if (p.search.value) { | |
this.searchInput.val(p.search.value); | |
} else if (p.filter) { | |
this.searchInput.val(p.filter); | |
} | |
if (this.searchInput.val() !== '') { | |
this._filter.apply(this.searchInput, [this.availItems]); | |
} | |
this._regsearch(this.searchInput, this.searchType); | |
this.searchInput.show(); | |
} else { | |
if (p.filter) { | |
this._filter.apply(p.filter, [this.availItems]); | |
} | |
} | |
// Save Sizes | |
this.sizes = { | |
'bodyWidth': ( (p.width == 'auto') ? (this.options.width = this.element.width()) : (p.width ? p.width : 0) ), | |
'bodyHeight': ( (p.height == 'auto') ? (this.options.height = this.element.height()) : (p.height ? p.height : 0) ), | |
'minWidth': p.minWidth || Math.floor(this.element.width() * 0.5) | |
} | |
// Resizable | |
this._resize(); | |
if (p.resizable) { | |
this.container.resizable({ | |
grid: [10, 10], | |
handles: p.resizable, | |
maxWidth: (p.maxWidth || false), | |
minWidth: self.sizes.minWidth, | |
maxHeight: (p.maxHeight || false), | |
minHeight: (p.minHeight || 80), | |
resize: function() { | |
self.sizes.bodyWidth = self.container.width(); | |
self.sizes.bodyHeight = self.container.height(); | |
self._resize(); | |
} | |
}); | |
} | |
// Sortable | |
if (this.options.sort) { | |
var sortopts = { | |
appendTo: self.container, | |
containment: self.container, | |
connectWith: '.connected-list', | |
forceHelperSize: true, | |
forcePlaceholderSize: true, | |
placeholder: 'ui-state-highlight', | |
revert: false | |
}; | |
this.availItems.bind('sortreceive', function(event, ui) { | |
ui.item.data('optionLink').attr('selected', false); | |
self.count -= 1; | |
self._updcount(); | |
self._updoption(ui.item, false, true); | |
}).bind('sortbeforestop', function(event, ui) { | |
ui.helper.removeClass('ui-multiselect-cloned'); | |
}).bind('sortstop', function(event, ui) { | |
self.availItems.find('li').each(function() { | |
if ($(this).data('optionLink')) { | |
$(this).data('optionLink').remove().appendTo(self.element); | |
} | |
}); | |
}).bind('sortstart', function(event, ui) { | |
ui.helper.addClass('ui-multiselect-cloned'); | |
}).sortable(sortopts); | |
this.selectItems.bind('sortreceive', function(event, ui) { | |
ui.item.data('optionLink').attr('selected', true); | |
self.count += 1; | |
self._updcount(); | |
self._updoption(ui.item, true, true); | |
}).bind('sortbeforestop', function(event, ui) { | |
ui.helper.removeClass('ui-multiselect-cloned'); | |
}).bind('sortstop', function(event, ui) { | |
self.selectItems.find('li').each(function() { | |
if ($(this).data('optionLink')) { | |
$(this).data('optionLink').remove().appendTo(self.element); | |
} | |
}); | |
}).bind('sortstart', function(event, ui) { | |
ui.helper.addClass('ui-multiselect-cloned'); | |
}).sortable(sortopts); | |
} | |
this._busy(false); | |
}, | |
// UI FUNCTION _setOption | |
// @param string key | |
// @param mixed value | |
_setOption: function(key, value) { | |
var self = this, u = 'undefined', p = this.options; | |
switch (key) { | |
// Set the busy state | |
case 'busy': | |
if (value) { | |
this._busy(true); | |
} else { | |
this._busy(false); | |
} | |
break; | |
// Manipulate the multiselect options | |
// Changes the selected status | |
case 'change': | |
this.change(value); | |
break; | |
// Update all datas, if it is an object | |
case 'data': | |
this._initlists(data); | |
this.refresh(); | |
break; | |
// Empty multiselect | |
case 'empty': | |
this.empty(); | |
break; | |
// Insert new options to the multiselect | |
case 'insert': | |
this.change(value); | |
break; | |
// Remove some options from the multiselect | |
case 'remove': | |
this.remove(value); | |
break; | |
// Update the list | |
case 'update': | |
case 'refresh': | |
this.refresh(); | |
break; | |
// Set a new filter or remove the filter | |
case 'filter': | |
if (value) { | |
this.searchInput.val(value); | |
this._filter.apply(this.searchInput, [self.availItems]); | |
} | |
break; | |
// Update the 'removeAll' and/or 'selectAll' buttons | |
case 'icons': | |
if (typeof(value['removeAll']) !== u) { | |
var v = value['removeAll']; | |
if (v) { | |
if (typeof(v) == 'boolean') { | |
v = p.icons.removeAll; | |
} | |
this.removeAll.removeClass(p.icons.removeAll).addClass(v).show().click(function() { | |
self._makelists(self.element.find('option').removeAttr('selected')); | |
return false; | |
}); | |
} else { | |
this.removeAllIcon.hide(); | |
} | |
} | |
if (typeof(value['selectAll']) !== u) { | |
var v = value['selectAll']; | |
if (v) { | |
if (typeof(v) == 'boolean') { | |
v = p.icons.selectAll; | |
} | |
this.selectAllIcon.removeClass(p.icons.selectAll).addClass(v).show().click(function() { | |
self._makelists(self.element.find('option').attr('selected', 'selected')); | |
return false; | |
}); | |
} else { | |
this.selectAllIcon.hide(); | |
} | |
} | |
break; | |
// Enable or disable the resizable | |
case 'resizable': | |
this.container.resizable('destroy'); | |
if (value) { | |
this.body.resizable({ | |
grid: [10, 10], | |
handles: (typeof(value) !== 'boolean' && typeof(value) == 'string') ? value : p.resizable, | |
maxWidth: (p.maxWidth || false), minWidth: self.sizes.minWidth, | |
maxHeight: (p.maxHeight || false), minHeight: (p.minHeight || 80), | |
resize: function() { | |
self.sizes.bodyWidth = self.container.width(); | |
self.sizes.bodyHeight = self.container.height(); | |
self._resize(); | |
} | |
}); | |
} | |
break; | |
// Set new search input | |
case 'search': | |
if (typeof(value['input']) !== u && value['input']) { | |
this.searchType = false; | |
if (('' + value['input']).substring(0, 6) == '<input' || ('' + value['input']).substring(0, 7) == '<select') { | |
if (('' + value['input']).substring(0, 7) == '<select') { | |
this.searchType = 'select'; | |
} else { | |
this.searchType = 'input'; | |
} | |
this.searchInput = $(value['input']).appendTo(this.availText).hide(); | |
} | |
if (!this.searchType) { | |
this.searchInput = $('<input type="text" size="20" value="" />').appendTo(this.availText).hide(); | |
this.searchType = 'input'; | |
} | |
} | |
if (typeof(value['enabled']) !== u) { | |
if (value['enabled']) { | |
this._regsearch(this.searchInput, this.searchType); | |
this.searchInput.show(); | |
} else { | |
this.searchInput.hide(); | |
} | |
} | |
if (typeof(value['value']) !== u) { | |
if (value['value']) { | |
this.searchInput.val(value['value']); | |
this._filter.apply(this.searchInput, [self.availItems]); | |
} | |
} | |
break; | |
// Set new maxWidth | |
case 'maxWidth': | |
this.sizes.maxWidth = (this.options.maxWidth = (value ? Max.abs(parseInt(value, 10)) : p.maxWidth) ); | |
break; | |
// Set new maxHeight | |
case 'maxHeight': | |
this.sizes.maxWidth = (this.options.maxHeight = (value ? Max.abs(parseInt(value, 10)) : p.maxHeight) ); | |
break; | |
// Set new width | |
case 'width': | |
this.sizes.bodyWidth = ( (value == 'auto') ? (this.options.width = this.element.width()) : (value ? (this.options.width = value) : p.width) ); | |
this._resize(); | |
break; | |
// Set new height | |
case 'height': | |
this.sizes.bodyHeight = ( (value == 'auto') ? (this.options.height = this.element.height()) : (value ? (this.options.height = value) : p.height) ); | |
this._resize(); | |
break; | |
} | |
}, | |
// UI FUNCTION | |
// Destroy (remove) the Multiselect Widget | |
destroy: function() { | |
this.element.show(); | |
this.container.remove(); | |
$.Widget.prototype.destroy.apply(this, arguments); | |
}, | |
// UI FUNCTION | |
// Enable or disable | |
enabled: function(state) { | |
if (typeof(state) !== 'undefined') { | |
if (state) { | |
this.container.removeClass('ui-state-disabled'); | |
this.container.find('li').removeClass('ui-state-disabled'); | |
this.element.removeAttr('disabled'); | |
} | |
else { | |
this.container.addClass('ui-state-disabled'); | |
this.container.find('li').addClass('ui-state-disabled'); | |
this.element.attr('disabled', true); | |
} | |
} | |
return !this.element.attr('disabled'); | |
}, | |
// UI FUNCTION | |
// Update after html append or insert | |
refresh: function() { | |
this._makelists(this.element.find('option')); | |
}, | |
// UI FUNCTION | |
// Changing selected status | |
change: function(value) { | |
var data = { change: value }; | |
this._initlists(data); | |
this.refresh(); | |
}, | |
// UI FUNCTION | |
// Removing all options | |
empty: function() { | |
var data = { empty: true }; | |
this._initlists(data); | |
this.refresh(); | |
}, | |
// UI FUNCTION | |
// insert new options | |
insert: function(value) { | |
var data = { insert: value }; | |
this._initlists(data); | |
this.refresh(); | |
}, | |
// UI FUNCTION | |
// remove options | |
remove: function(value) { | |
var data = { remove: value }; | |
this._initlists(data); | |
this.refresh(); | |
}, | |
// UI FUNCTION | |
// get values | |
values: function() { | |
var value = 'option' | |
if (typeof(arguments[0]) !== 'undefined') { | |
if (typeof(arguments[0]) == 'string') { | |
var key = ('' + arguments[0]).toLowerCase(); | |
switch (key) { | |
case 'selected': | |
case 'true': | |
case '1': | |
value = 'option:selected'; | |
break; | |
case 'notselected': | |
case '!selected': | |
case 'false': | |
case '0': | |
value = 'option:not(:selected)'; | |
break; | |
default: | |
value = 'option[' + this._findvalue(arguments[0]) + ']'; | |
break; | |
} | |
} else if (typeof(arguments[0]) == 'boolean') { | |
if (arguments[0]) { | |
value = 'option:selected' | |
} else { | |
value = 'option:not(:selected)' | |
} | |
} | |
} | |
return $.map( | |
this.element.find(value), | |
function (item, i) { | |
return $(item).val(); | |
} | |
); | |
}, | |
// UI FUNCTION | |
// get selected | |
selected: function(value) { | |
value = 'option[' + this._findvalue(value) + ']'; | |
return $.map( | |
this.element.find(value), | |
function (item, i) { | |
return $(item).attr('selected') ? true : false; | |
} | |
); | |
} | |
}); | |
$.extend($.ui.multiselect, { | |
locale: { | |
selectAll : 'Select all', | |
removeAll : 'Remove all', | |
selectItem : 'Select', | |
removeItem : 'Remove', | |
countItems : '{count} items selected', | |
search : 'Search', | |
busy : 'Loading' | |
} | |
}); | |
})(jQuery); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment