From eb25fb37077e83bb1945c7254076cd4c83ff9dd8 Mon Sep 17 00:00:00 2001 From: Weidong Shao Date: Fri, 3 Jan 2014 00:24:17 +0000 Subject: [PATCH] Add multi-select library --- public/lib/images/multiple-select.png | Bin 0 -> 3342 bytes public/lib/jquery.multiple.select.js | 390 ++++++++++++++++++++++++++ public/lib/multiple-select.css | 170 +++++++++++ 3 files changed, 560 insertions(+) create mode 100644 public/lib/images/multiple-select.png create mode 100644 public/lib/jquery.multiple.select.js create mode 100644 public/lib/multiple-select.css diff --git a/public/lib/images/multiple-select.png b/public/lib/images/multiple-select.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7ba608ea846d4873f84e00455ee2d1bbe4d13a GIT binary patch literal 3342 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 Y016sCsn^Dnga7~l07*qoM6N<$f>N + * @version 1.0.5 + * + * http://wenzhixin.net.cn/p/multiple-select/ + */ + +(function($) { + + 'use strict'; + + function MultipleSelect($el, options) { + var that = this, + elWidth = $el.width(); + + this.$el = $el.hide(); + this.options = options; + + this.$parent = $('
'); + this.$choice = $(''); + this.$drop = $('
'); + this.$el.after(this.$parent); + this.$parent.append(this.$choice); + this.$parent.append(this.$drop); + + if (this.$el.prop('disabled')) { + this.$choice.addClass('disabled'); + } + this.$choice.css('width', elWidth + 'px'); + this.$drop.css({ + width: (options.width || elWidth) + 'px' + }); + + $('body').click(function(e) { + if ($(e.target)[0] === that.$choice[0] || + $(e.target).parents('.ms-choice')[0] === that.$choice[0]) { + return; + } + if (($(e.target)[0] === that.$drop[0] || + $(e.target).parents('.ms-drop')[0] !== that.$drop[0]) && + that.options.isopen) { + that.close(); + } + }); + + if (this.options.isopen) { + this.open(); + } + } + + MultipleSelect.prototype = { + constructor : MultipleSelect, + + init: function() { + var that = this, + html = []; + if (this.options.filter) { + html.push( + '' + ); + } + html.push('
    '); + if (this.options.selectAll) { + html.push( + '
  • ', + '', + '
  • ' + ); + } + $.each(this.$el.children(), function(i, elm) { + html.push(that.optionToHtml(i, elm)); + }); + html.push('
'); + this.$drop.html(html.join('')); + this.$drop.find('ul').css('max-height', this.options.maxHeight + 'px'); + this.$drop.find('.multiple').css('width', this.options.multipleWidth + 'px'); + + this.$searchInput = this.$drop.find('.ms-search input'); + this.$selectAll = this.$drop.find('input[name="selectAll"]'); + this.$selectGroups = this.$drop.find('input[name="selectGroup"]'); + this.$selectItems = this.$drop.find('input[name="selectItem"]:enabled'); + this.$disableItems = this.$drop.find('input[name="selectItem"]:disabled'); + this.events(); + this.update(); + }, + + optionToHtml: function(i, elm, group, groupDisabled) { + var that = this, + $elm = $(elm), + html = [], + multiple = this.options.multiple, + disabled; + + if ($elm.is('option')) { + var value = $elm.val(), + text = $elm.text(), + selected = $elm.prop('selected'); + + disabled = groupDisabled || $elm.prop('disabled'); + html.push( + '', + '', + ' ', + text, + '', + '' + ); + } else if (!group && $elm.is('optgroup')) { + var _group = 'group_' + i, + label = $elm.attr('label'); + + disabled = $elm.prop('disabled'); + html.push( + '
  • ', + '', + '
  • '); + $.each($elm.children(), function(i, elm) { + html.push(that.optionToHtml(i, elm, _group, disabled)); + }); + } + return html.join(''); + }, + + events: function() { + var that = this; + this.$choice.off('click').on('click', function() { + that[that.options.isopen ? 'close' : 'open'](); + }); + this.$parent.off('keydown').on('keydown', function(e) { + switch (e.which) { + case 27: // esc key + that.close(); + that.$choice.focus(); + break; + } + }); + this.$searchInput.off('keyup').on('keyup', function() { + that.filter(); + }); + this.$selectAll.off('click').on('click', function() { + var checked = $(this).prop('checked'), + $items = that.$selectItems.filter(':visible'); + if ($items.length === that.$selectItems.length) { + that[checked ? 'checkAll' : 'uncheckAll'](); + } else { // when the filter option is true + that.$selectGroups.prop('checked', checked); + $items.prop('checked', checked); + that.update(); + } + }); + this.$selectGroups.off('click').on('click', function() { + var group = $(this).parent().attr('data-group'), + $items = that.$selectItems.filter(':visible'), + $children = $items.filter('[data-group="' + group + '"]'), + checked = $children.length !== $children.filter(':checked').length; + $children.prop('checked', checked); + that.updateSelectAll(); + that.update(); + that.options.onOptgroupClick({ + label: $(this).parent().text(), + checked: checked, + children: $children.get() + }); + }); + this.$selectItems.off('click').on('click', function() { + that.updateSelectAll(); + that.update(); + that.updateOptGroupSelect(); + that.options.onClick({ + label: $(this).parent().text(), + value: $(this).val(), + checked: $(this).prop('checked') + }); + }); + }, + + open: function() { + if (this.$choice.hasClass('disabled')) { + return; + } + this.options.isopen = true; + this.$choice.find('>div').addClass('open'); + this.$drop.show(); + if (this.options.filter) { + this.$searchInput.val(''); + this.filter(); + } + this.options.onOpen(); + }, + + close: function() { + this.options.isopen = false; + this.$choice.find('>div').removeClass('open'); + this.$drop.hide(); + this.options.onClose(); + }, + + update: function() { + var selects = this.getSelects('text'), + $span = this.$choice.find('>span'); + if (selects.length) { + $span.removeClass('placeholder').html(selects.join(', ')); + } else { + $span.addClass('placeholder').html(this.options.placeholder); + } + // set selects to select + this.$el.val(this.getSelects()); + }, + + updateSelectAll: function() { + var $items = this.$selectItems.filter(':visible'); + this.$selectAll.prop('checked', $items.length && + $items.length === $items.filter(':checked').length); + }, + + updateOptGroupSelect: function() { + var $items = this.$selectItems.filter(':visible'); + $.each(this.$selectGroups, function(i, val) { + var group = $(val).parent().attr('data-group'), + $children = $items.filter('[data-group="' + group + '"]'); + $(val).prop('checked', $children.length && + $children.length === $children.filter(':checked').length); + }); + }, + + //value or text, default: 'value' + getSelects: function(type) { + var that = this, + texts = [], + values = []; + this.$drop.find('input[name="selectItem"]:checked').each(function() { + texts.push($(this).parent().text()); + values.push($(this).val()); + }); + + if (type === 'text' && this.$selectGroups.length) { + texts = []; + this.$selectGroups.each(function() { + var html = [], + text = $.trim($(this).parent().text()), + group = $(this).parent().data('group'), + $children = that.$drop.find('[name="selectItem"][data-group="' + group + '"]'), + $selected = $children.filter(':checked'); + + if ($selected.length === 0) { + return; + } + + html.push('['); + html.push(text); + if ($children.length > $selected.length) { + var list = []; + $selected.each(function() { + list.push($(this).parent().text()); + }); + html.push(': ' + list.join(', ')); + } + html.push(']'); + texts.push(html.join('')); + }); + } + return type === 'text' ? texts : values; + }, + + setSelects: function(values) { + var that = this; + this.$selectItems.prop('checked', false); + $.each(values, function(i, value) { + that.$selectItems.filter('[value="' + value + '"]').prop('checked', true); + }); + this.$selectAll.prop('checked', this.$selectItems.length === + this.$selectItems.filter(':checked').length); + this.update(); + }, + + enable: function() { + this.$choice.removeClass('disabled'); + }, + + disable: function() { + this.$choice.addClass('disabled'); + }, + + checkAll: function() { + this.$selectItems.prop('checked', true); + this.$selectGroups.prop('checked', true); + this.$selectAll.prop('checked', true); + this.update(); + this.options.onCheckAll(); + }, + + uncheckAll: function() { + this.$selectItems.prop('checked', false); + this.$selectGroups.prop('checked', false); + this.$selectAll.prop('checked', false); + this.update(); + this.options.onUncheckAll(); + }, + + refresh: function() { + this.init(); + }, + + filter: function() { + var that = this, + text = $.trim(this.$searchInput.val()).toLowerCase(); + if (text.length === 0) { + this.$selectItems.parent().show(); + this.$disableItems.parent().show(); + this.$selectGroups.parent().show(); + } else { + this.$selectItems.each(function() { + var $parent = $(this).parent(); + $parent[$parent.text().toLowerCase().indexOf(text) < 0 ? 'hide' : 'show'](); + }); + this.$disableItems.parent().hide(); + this.$selectGroups.each(function() { + var $parent = $(this).parent(); + var group = $parent.attr('data-group'), + $items = that.$selectItems.filter(':visible'); + $parent[$items.filter('[data-group="' + group + '"]').length === 0 ? 'hide' : 'show'](); + }); + } + this.updateOptGroupSelect(); + this.updateSelectAll(); + } + }; + + $.fn.multipleSelect = function() { + var option = arguments[0], + args = arguments, + + value, + allowedMethods = ['getSelects', 'setSelects', 'enable', 'disable', 'checkAll', 'uncheckAll', 'refresh']; + + this.each(function() { + var $this = $(this), + data = $this.data('multipleSelect'), + options = $.extend({}, $.fn.multipleSelect.defaults, typeof option === 'object' && option); + + if (!data) { + data = new MultipleSelect($this, options); + $this.data('multipleSelect', data); + } + + if (typeof option === 'string') { + if ($.inArray(option, allowedMethods) < 0) { + throw "Unknown method: " + option; + } + value = data[option](args[1]); + } else { + data.init(); + } + }); + + return value ? value : this; + }; + + $.fn.multipleSelect.defaults = { + isopen: false, + placeholder: '', + selectAll: true, + selectAllText: 'Select all', + multiple: false, + multipleWidth: 80, + filter: false, + width: undefined, + maxHeight: 250, + + onOpen: function() {return false;}, + onClose: function() {return false;}, + onCheckAll: function() {return false;}, + onUncheckAll: function() {return false;}, + onOptgroupClick: function() {return false;}, + onClick: function() {return false;} + }; +})(jQuery); diff --git a/public/lib/multiple-select.css b/public/lib/multiple-select.css new file mode 100644 index 0000000..765e9fe --- /dev/null +++ b/public/lib/multiple-select.css @@ -0,0 +1,170 @@ +/** + * @author zhixin wen + */ + +.ms-parent { + display: inline-block; + position: relative; + vertical-align: middle; +} + +.ms-choice { + display: block; + height: 26px; + padding: 0; + overflow: hidden; + cursor: pointer; + border: 1px solid #aaa; + text-align: left; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + background-color: #fff; +} + +.ms-choice.disabled { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.ms-choice > span { + position: absolute; + top: 0; + left: 0; + right: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + padding-left: 8px; +} + +.ms-choice > span.placeholder { + color: #999; +} + +.ms-choice > div { + position: absolute; + top: 0; + right: 0; + width: 20px; + height: 25px; + background: url('images/multiple-select.png') right top no-repeat; +} + +.ms-choice > div.open { + background: url('images/multiple-select.png') left top no-repeat; +} + +.ms-drop { + overflow: hidden; + display: none; + margin-top: -1px; + padding: 0; + position: absolute; + z-index: 1000; + top: 100%; + background: #fff; + color: #000; + border: 1px solid #aaa; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + + +.ms-search { + display: inline-block; + margin: 0; + min-height: 26px; + padding: 4px; + position: relative; + white-space: nowrap; + width: 100%; + z-index: 10000; +} + +.ms-search input { + width: 100%; + height: auto !important; + min-height: 24px; + padding: 0 20px 0 5px; + margin: 0; + outline: 0; + font-family: sans-serif; + font-size: 1em; + border: 1px solid #aaa; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + background: #fff url('multiple-select.png') no-repeat 100% -22px; + background: url('multiple-select.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); + background: url('multiple-select.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('multiple-select.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('multiple-select.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); + background: url('multiple-select.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); + background: url('multiple-select.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%); +} + +.ms-search, .ms-search input { + -webkit-box-sizing: border-box; + -khtml-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.ms-drop ul { + overflow: auto; + margin: 0; + padding: 5px 8px; +} + +.ms-drop ul > li { + list-style: none; + display: list-item; + background-image: none; + position: static; +} + +.ms-drop ul > li .disabled { + opacity: .35; + filter: Alpha(Opacity=35); +} + +.ms-drop ul > li.multiple { + display: block; + float: left; +} + +.ms-drop ul > li.group { + clear: both; +} + +.ms-drop ul > li.multiple label { + width: 100%; + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ms-drop ul > li label.optgroup { + font-weight: bold; +} + +.ms-drop input[type="checkbox"] { + vertical-align: middle; +}