Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,30 @@ | |||
/* Multiselect | |||
----------------------------------*/ | |||
|
|||
.ui-multiselect { border: solid 1px; font-size: 0.8em; } | |||
.ui-multiselect ul { -moz-user-select: none; } | |||
.ui-multiselect li { margin: 0; padding: 0; cursor: default; line-height: 20px; height: 20px; font-size: 11px; list-style: none; } | |||
.ui-multiselect li a { color: #999; text-decoration: none; padding: 0; display: block; float: left; cursor: pointer;} | |||
.ui-multiselect li.ui-draggable-dragging { padding-left: 10px; } | |||
|
|||
.ui-multiselect div.selected { position: relative; padding: 0; margin: 0; border: 0; float:left; } | |||
.ui-multiselect ul.selected { position: relative; padding: 0; overflow: auto; overflow-x: hidden; background: #fff; margin: 0; list-style: none; border: 0; position: relative; width: 100%; } | |||
.ui-multiselect ul.selected li { } | |||
|
|||
.ui-multiselect div.available { position: relative; padding: 0; margin: 0; border: 0; float:left; border-left: 1px solid; } | |||
.ui-multiselect ul.available { position: relative; padding: 0; overflow: auto; overflow-x: hidden; background: #fff; margin: 0; list-style: none; border: 0; width: 100%; } | |||
.ui-multiselect ul.available li { padding-left: 10px; } | |||
|
|||
.ui-multiselect .ui-state-default { border: none; margin-bottom: 1px; position: relative; padding-left: 20px;} | |||
.ui-multiselect .ui-state-hover { border: none; } | |||
.ui-multiselect .ui-widget-header {border: none; font-size: 11px; margin-bottom: 1px;} | |||
|
|||
.ui-multiselect .add-all { float: right; padding: 7px;} | |||
.ui-multiselect .remove-all { float: right; padding: 7px;} | |||
.ui-multiselect .search { float: left; padding: 4px;} | |||
.ui-multiselect .count { float: left; padding: 7px;} | |||
|
|||
.ui-multiselect li span.ui-icon-arrowthick-2-n-s { position: absolute; left: 2px; } | |||
.ui-multiselect li a.action { position: absolute; right: 2px; top: 2px; } | |||
|
|||
.ui-multiselect input.search { height: 14px; padding: 1px; opacity: 0.5; margin: 4px; width: 100px; } |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,314 @@ | |||
/* | |||
* jQuery UI Multiselect | |||
* | |||
* Authors: | |||
* Michael Aufreiter (quasipartikel.at) | |||
* Yanick Rochon (yanick.rochon[at]gmail[dot]com) | |||
* | |||
* Dual licensed under the MIT (MIT-LICENSE.txt) | |||
* and GPL (GPL-LICENSE.txt) licenses. | |||
* | |||
* http://www.quasipartikel.at/multiselect/ | |||
* | |||
* | |||
* Depends: | |||
* ui.core.js | |||
* ui.sortable.js | |||
* | |||
* Optional: | |||
* localization (http://plugins.jquery.com/project/localisation) | |||
* scrollTo (http://plugins.jquery.com/project/ScrollTo) | |||
* | |||
* Todo: | |||
* Make batch actions faster | |||
* Implement dynamic insertion through remote calls | |||
*/ | |||
|
|||
|
|||
(function($) { | |||
|
|||
$.widget("ui.multiselect", { | |||
_init: function() { | |||
this.element.hide(); | |||
this.id = this.element.attr("id"); | |||
this.container = $('<div class="ui-multiselect ui-helper-clearfix ui-widget"></div>').insertAfter(this.element); | |||
this.count = 0; // number of currently selected options | |||
this.selectedContainer = $('<div class="selected"></div>').appendTo(this.container); | |||
this.availableContainer = $('<div class="available"></div>').appendTo(this.container); | |||
this.selectedActions = $('<div class="actions ui-widget-header ui-helper-clearfix"><span class="count">0 '+$.ui.multiselect.locale.itemsCount+'</span><a href="#" class="remove-all">'+$.ui.multiselect.locale.removeAll+'</a></div>').appendTo(this.selectedContainer); | |||
this.availableActions = $('<div class="actions ui-widget-header ui-helper-clearfix"><input type="text" class="search empty ui-widget-content ui-corner-all"/><a href="#" class="add-all">'+$.ui.multiselect.locale.addAll+'</a></div>').appendTo(this.availableContainer); | |||
this.selectedList = $('<ul class="selected connected-list"><li class="ui-helper-hidden-accessible"></li></ul>').bind('selectstart', function(){return false;}).appendTo(this.selectedContainer); | |||
this.availableList = $('<ul class="available connected-list"><li class="ui-helper-hidden-accessible"></li></ul>').bind('selectstart', function(){return false;}).appendTo(this.availableContainer); | |||
|
|||
var that = this; | |||
|
|||
// set dimensions | |||
this.container.width(this.element.width()+1); | |||
this.selectedContainer.width(Math.floor(this.element.width()*this.options.dividerLocation)); | |||
this.availableContainer.width(Math.floor(this.element.width()*(1-this.options.dividerLocation))); | |||
|
|||
// fix list height to match <option> depending on their individual header's heights | |||
this.selectedList.height(Math.max(this.element.height()-this.selectedActions.height(),1)); | |||
this.availableList.height(Math.max(this.element.height()-this.availableActions.height(),1)); | |||
|
|||
if ( !this.options.animated ) { | |||
this.options.show = 'show'; | |||
this.options.hide = 'hide'; | |||
} | |||
|
|||
// init lists | |||
this._populateLists(this.element.find('option')); | |||
|
|||
// make selection sortable | |||
if (this.options.sortable) { | |||
$("ul.selected").sortable({ | |||
placeholder: 'ui-state-highlight', | |||
axis: 'y', | |||
update: function(event, ui) { | |||
// apply the new sort order to the original selectbox | |||
that.selectedList.find('li').each(function() { | |||
if ($(this).data('optionLink')) | |||
$(this).data('optionLink').remove().appendTo(that.element); | |||
}); | |||
}, | |||
receive: function(event, ui) { | |||
ui.item.data('optionLink').attr('selected', true); | |||
// increment count | |||
that.count += 1; | |||
that._updateCount(); | |||
// workaround, because there's no way to reference | |||
// the new element, see http://dev.jqueryui.com/ticket/4303 | |||
that.selectedList.children('.ui-draggable').each(function() { | |||
$(this).removeClass('ui-draggable'); | |||
$(this).data('optionLink', ui.item.data('optionLink')); | |||
$(this).data('idx', ui.item.data('idx')); | |||
that._applyItemState($(this), true); | |||
}); | |||
|
|||
// workaround according to http://dev.jqueryui.com/ticket/4088 | |||
setTimeout(function() { ui.item.remove(); }, 1); | |||
} | |||
}); | |||
} | |||
|
|||
// set up livesearch | |||
if (this.options.searchable) { | |||
this._registerSearchEvents(this.availableContainer.find('input.search')); | |||
} else { | |||
$('.search').hide(); | |||
} | |||
|
|||
// batch actions | |||
$(".remove-all").click(function() { | |||
that._populateLists(that.element.find('option').removeAttr('selected')); | |||
return false; | |||
}); | |||
$(".add-all").click(function() { | |||
that._populateLists(that.element.find('option').attr('selected', 'selected')); | |||
return false; | |||
}); | |||
}, | |||
destroy: function() { | |||
this.element.show(); | |||
this.container.remove(); | |||
|
|||
$.widget.prototype.destroy.apply(this, arguments); | |||
}, | |||
_populateLists: function(options) { | |||
this.selectedList.children('.ui-element').remove(); | |||
this.availableList.children('.ui-element').remove(); | |||
this.count = 0; | |||
|
|||
var that = this; | |||
var items = $(options.map(function(i) { | |||
var item = that._getOptionNode(this).appendTo(this.selected ? that.selectedList : that.availableList).show(); | |||
|
|||
if (this.selected) that.count += 1; | |||
that._applyItemState(item, this.selected); | |||
item.data('idx', i); | |||
return item[0]; | |||
})); | |||
|
|||
// update count | |||
this._updateCount(); | |||
}, | |||
_updateCount: function() { | |||
this.selectedContainer.find('span.count').text(this.count+" "+$.ui.multiselect.locale.itemsCount); | |||
}, | |||
_getOptionNode: function(option) { | |||
option = $(option); | |||
var node = $('<li class="ui-state-default ui-element" title="'+option.text()+'"><span class="ui-icon"/>'+option.text()+'<a href="#" class="action"><span class="ui-corner-all ui-icon"/></a></li>').hide(); | |||
node.data('optionLink', option); | |||
return node; | |||
}, | |||
// clones an item with associated data | |||
// didn't find a smarter away around this | |||
_cloneWithData: function(clonee) { | |||
var clone = clonee.clone(); | |||
clone.data('optionLink', clonee.data('optionLink')); | |||
clone.data('idx', clonee.data('idx')); | |||
return clone; | |||
}, | |||
_setSelected: function(item, selected) { | |||
item.data('optionLink').attr('selected', selected); | |||
|
|||
if (selected) { | |||
var selectedItem = this._cloneWithData(item); | |||
item[this.options.hide](this.options.animated, function() { $(this).remove(); }); | |||
selectedItem.appendTo(this.selectedList).hide()[this.options.show](this.options.animated); | |||
|
|||
this._applyItemState(selectedItem, true); | |||
return selectedItem; | |||
} else { | |||
|
|||
// look for successor based on initial option index | |||
var items = this.availableList.find('li'), comparator = this.options.nodeComparator; | |||
var succ = null, i = item.data('idx'), direction = comparator(item, $(items[i])); | |||
|
|||
// TODO: test needed for dynamic list populating | |||
if ( direction ) { | |||
while (i>=0 && i<items.length) { | |||
direction > 0 ? i++ : i--; | |||
if ( direction != comparator(item, $(items[i])) ) { | |||
// going up, go back one item down, otherwise leave as is | |||
succ = items[direction > 0 ? i : i+1]; | |||
break; | |||
} | |||
} | |||
} else { | |||
succ = items[i]; | |||
} | |||
|
|||
var availableItem = this._cloneWithData(item); | |||
succ ? availableItem.insertBefore($(succ)) : availableItem.appendTo(this.availableList); | |||
item[this.options.hide](this.options.animated, function() { $(this).remove(); }); | |||
availableItem.hide()[this.options.show](this.options.animated); | |||
|
|||
this._applyItemState(availableItem, false); | |||
return availableItem; | |||
} | |||
}, | |||
_applyItemState: function(item, selected) { | |||
if (selected) { | |||
if (this.options.sortable) | |||
item.children('span').addClass('ui-icon-arrowthick-2-n-s').removeClass('ui-helper-hidden').addClass('ui-icon'); | |||
else | |||
item.children('span').removeClass('ui-icon-arrowthick-2-n-s').addClass('ui-helper-hidden').removeClass('ui-icon'); | |||
item.find('a.action span').addClass('ui-icon-minus').removeClass('ui-icon-plus'); | |||
this._registerRemoveEvents(item.find('a.action')); | |||
|
|||
} else { | |||
item.children('span').removeClass('ui-icon-arrowthick-2-n-s').addClass('ui-helper-hidden').removeClass('ui-icon'); | |||
item.find('a.action span').addClass('ui-icon-plus').removeClass('ui-icon-minus'); | |||
this._registerAddEvents(item.find('a.action')); | |||
} | |||
|
|||
this._registerHoverEvents(item); | |||
}, | |||
// taken from John Resig's liveUpdate script | |||
_filter: function(list) { | |||
var input = $(this); | |||
var rows = list.children('li'), | |||
cache = rows.map(function(){ | |||
|
|||
return $(this).text().toLowerCase(); | |||
}); | |||
|
|||
var 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(); | |||
}); | |||
} | |||
}, | |||
_registerHoverEvents: function(elements) { | |||
elements.removeClass('ui-state-hover'); | |||
elements.mouseover(function() { | |||
$(this).addClass('ui-state-hover'); | |||
}); | |||
elements.mouseout(function() { | |||
$(this).removeClass('ui-state-hover'); | |||
}); | |||
}, | |||
_registerAddEvents: function(elements) { | |||
var that = this; | |||
elements.click(function() { | |||
var item = that._setSelected($(this).parent(), true); | |||
that.count += 1; | |||
that._updateCount(); | |||
return false; | |||
}) | |||
// make draggable | |||
.each(function() { | |||
$(this).parent().draggable({ | |||
connectToSortable: 'ul.selected', | |||
helper: function() { | |||
var selectedItem = that._cloneWithData($(this)).width($(this).width() - 50); | |||
selectedItem.width($(this).width()); | |||
return selectedItem; | |||
}, | |||
appendTo: '.ui-multiselect', | |||
containment: '.ui-multiselect', | |||
revert: 'invalid' | |||
}); | |||
}); | |||
}, | |||
_registerRemoveEvents: function(elements) { | |||
var that = this; | |||
elements.click(function() { | |||
that._setSelected($(this).parent(), false); | |||
that.count -= 1; | |||
that._updateCount(); | |||
return false; | |||
}); | |||
}, | |||
_registerSearchEvents: function(input) { | |||
var that = this; | |||
|
|||
input.focus(function() { | |||
$(this).addClass('ui-state-active'); | |||
}) | |||
.blur(function() { | |||
$(this).removeClass('ui-state-active'); | |||
}) | |||
.keypress(function(e) { | |||
if (e.keyCode == 13) | |||
return false; | |||
}) | |||
.keyup(function() { | |||
that._filter.apply(this, [that.availableList]); | |||
}); | |||
} | |||
}); | |||
|
|||
$.extend($.ui.multiselect, { | |||
defaults: { | |||
sortable: true, | |||
searchable: true, | |||
animated: 'fast', | |||
show: 'slideDown', | |||
hide: 'slideUp', | |||
dividerLocation: 0.6, | |||
nodeComparator: function(node1,node2) { | |||
var text1 = node1.text(), | |||
text2 = node2.text(); | |||
return text1 == text2 ? 0 : (text1 < text2 ? -1 : 1); | |||
} | |||
}, | |||
locale: { | |||
addAll:'Add all', | |||
removeAll:'Remove all', | |||
itemsCount:'items selected' | |||
} | |||
}); | |||
|
|||
})(jQuery); |