(function ($, window, document, undefined) { var pluginName = "bootstrapDualListbox", defaults = { bootstrap2Compatible: false, filterTextClear: "show all", filterPlaceHolder: "Filter", moveSelectedLabel: "Move selected", moveAllLabel: "Move all", removeSelectedLabel: "Remove selected", removeAllLabel: "Remove all", moveOnSelect: true, preserveSelectionOnMove: false, selectedListLabel: false, nonSelectedListLabel: false, helperSelectNamePostfix: "_helper", selectorMinimalHeight: 100, showFilterInputs: true, nonSelectedFilter: "", selectedFilter: "", filterOnValues: false, doubleMove: false }, isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase()); function BootstrapDualListbox(element, options) { this.element = $(element); this.settings = $.extend({}, defaults, options); this._defaults = defaults; this._name = pluginName; this.init() } function triggerChangeEvent(dualListbox) { dualListbox.element.trigger("change") } function updateSelectionStates(dualListbox) { dualListbox.element.find("option").each(function (index, item) { var $item = $(item); if (typeof ($item.data("original-index")) === "undefined") { $item.data("original-index", dualListbox.elementCount++) } if (typeof ($item.data("_selected")) === "undefined") { $item.data("_selected", false) } }) } function changeSelectionState(dualListbox, original_index, selected) { dualListbox.element.find("option").each(function (index, item) { var $item = $(item); if ($item.data("original-index") === original_index) { $item.prop("selected", selected) } }) } function formatString(s, args) { return s.replace(/\{(\d+)\}/g, function (match, number) { return typeof args[number] !== "undefined" ? args[number] : match }) } function refreshInfo(dualListbox) { if (!dualListbox.settings.infoText) { return } var visible1 = dualListbox.elements.select1.find("option").length, visible2 = dualListbox.elements.select2.find("option").length, all1 = dualListbox.element.find("option").length - dualListbox.selectedElements, all2 = dualListbox.selectedElements, content = ""; if (all1 === 0) { content = dualListbox.settings.infoTextEmpty } else { if (visible1 === all1) { content = formatString(dualListbox.settings.infoText, [visible1, all1]) } else { content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]) } } dualListbox.elements.info1.html(content); dualListbox.elements.box1.toggleClass("filtered", !(visible1 === all1 || all1 === 0)); if (all2 === 0) { content = dualListbox.settings.infoTextEmpty } else { if (visible2 === all2) { content = formatString(dualListbox.settings.infoText, [visible2, all2]) } else { content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]) } } dualListbox.elements.info2.html(content); dualListbox.elements.box2.toggleClass("filtered", !(visible2 === all2 || all2 === 0)) } function refreshSelects(dualListbox) { dualListbox.selectedElements = 0; dualListbox.elements.select1.empty(); dualListbox.elements.select2.empty(); dualListbox.element.find("option").each(function (index, item) { var $item = $(item); if ($item.prop("selected")) { dualListbox.selectedElements++; dualListbox.elements.select2.append($item.clone(true).prop("selected", $item.data("_selected"))) } else if($item.attr("isshow")==="1") { dualListbox.elements.select1.append($item.clone(true).prop("selected", $item.data("_selected"))) } }); if (dualListbox.settings.showFilterInputs) { filter(dualListbox, 1); filter(dualListbox, 2) } refreshInfo(dualListbox) } function filter(dualListbox, selectIndex) { if (!dualListbox.settings.showFilterInputs) { return } saveSelections(dualListbox, selectIndex); dualListbox.elements["select" + selectIndex].empty().scrollTop(0); var regex = new RegExp($.trim(dualListbox.elements["filterInput" + selectIndex].val()), "gi"), options = dualListbox.element; if (selectIndex === 1) { options = options.find("option[isshow='1']").not(":selected") } else { options = options.find("option:selected") } options.each(function (index, item) { var $item = $(item), isFiltered = true; if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr("value").match(regex))) { isFiltered = false; dualListbox.elements["select" + selectIndex].append($item.clone(true).prop("selected", $item.data("_selected"))) } dualListbox.element.find("option").eq($item.data("original-index")).data("filtered" + selectIndex, isFiltered) }); refreshInfo(dualListbox) } function saveSelections(dualListbox, selectIndex) { dualListbox.elements["select" + selectIndex].find("option").each(function (index, item) { var $item = $(item); dualListbox.element.find("option").eq($item.data("original-index")).data("_selected", $item.prop("selected")) }) } function sortOptions(select) { select.find("option").sort(function (a, b) { return ($(a).data("original-index") > $(b).data("original-index")) ? 1 : -1 }).appendTo(select) } function clearSelections(dualListbox) { dualListbox.elements.select1.find("option").each(function () { dualListbox.element.find("option").data("_selected", false) }) } function move(dualListbox) { if (dualListbox.settings.preserveSelectionOnMove === "all" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1); saveSelections(dualListbox, 2) } else { if (dualListbox.settings.preserveSelectionOnMove === "moved" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1) } } dualListbox.elements.select1.find("option:selected").each(function (index, item) { var $item = $(item); if (!$item.data("filtered1")) { changeSelectionState(dualListbox, $item.data("original-index"), true) } }); refreshSelects(dualListbox); triggerChangeEvent(dualListbox); sortOptions(dualListbox.elements.select2) } function remove(dualListbox) { if (dualListbox.settings.preserveSelectionOnMove === "all" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1); saveSelections(dualListbox, 2) } else { if (dualListbox.settings.preserveSelectionOnMove === "moved" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 2) } } dualListbox.elements.select2.find("option:selected").each(function (index, item) { var $item = $(item); if (!$item.data("filtered2")) { changeSelectionState(dualListbox, $item.data("original-index"), false) } }); refreshSelects(dualListbox); triggerChangeEvent(dualListbox); sortOptions(dualListbox.elements.select1) } function moveAll(dualListbox) { if (dualListbox.settings.preserveSelectionOnMove === "all" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1); saveSelections(dualListbox, 2) } else { if (dualListbox.settings.preserveSelectionOnMove === "moved" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1) } } dualListbox.element.find("option[isshow='1']").each(function (index, item) { var $item = $(item); if (!$item.data("filtered1")) { $item.prop("selected", true) } }); refreshSelects(dualListbox); triggerChangeEvent(dualListbox) } function removeAll(dualListbox) { if (dualListbox.settings.preserveSelectionOnMove === "all" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 1); saveSelections(dualListbox, 2) } else { if (dualListbox.settings.preserveSelectionOnMove === "moved" && !dualListbox.settings.moveOnSelect) { saveSelections(dualListbox, 2) } } dualListbox.element.find("option").each(function (index, item) { var $item = $(item); if (!$item.data("filtered2")) { $item.prop("selected", false) } }); refreshSelects(dualListbox); triggerChangeEvent(dualListbox) } function upSort(dualListbox) { dualListbox.elements.select2.find("option:selected").each(function (index, item) { var $item = $(item); var $target = $item.prev(); $item.insertBefore($target) }) } function downSort(dualListbox) { dualListbox.elements.select2.find("option:selected").each(function (index, item) { var $item = $(item); var $target = $item.next(); $item.insertAfter($target) }) } function bindEvents(dualListbox) { dualListbox.elements.form.submit(function (e) { if (dualListbox.elements.filterInput1.is(":focus")) { e.preventDefault(); dualListbox.elements.filterInput1.focusout() } else { if (dualListbox.elements.filterInput2.is(":focus")) { e.preventDefault(); dualListbox.elements.filterInput2.focusout() } } }); dualListbox.element.on("bootstrapDualListbox.refresh", function (e, mustClearSelections) { dualListbox.refresh(mustClearSelections) }); dualListbox.elements.filterClear1.on("click", function () { dualListbox.setNonSelectedFilter("", true) }); dualListbox.elements.filterClear2.on("click", function () { dualListbox.setSelectedFilter("", true) }); dualListbox.elements.moveButton.on("click", function () { move(dualListbox) }); dualListbox.elements.moveAllButton.on("click", function () { moveAll(dualListbox) }); dualListbox.elements.removeButton.on("click", function () { remove(dualListbox) }); dualListbox.elements.removeAllButton.on("click", function () { removeAll(dualListbox) }); dualListbox.elements.upButton.on("click", function () { upSort(dualListbox) }); dualListbox.elements.downButton.on("click", function () { downSort(dualListbox) }); dualListbox.elements.filterInput1.on("change keyup", function () { filter(dualListbox, 1) }); dualListbox.elements.filterInput2.on("change keyup", function () { filter(dualListbox, 2) }); dualListbox.elements.filterInput2.on("change keyup", function () { filter(dualListbox, 2) }) } BootstrapDualListbox.prototype = { init: function () { this.container = $("" + '
' + '
' + " " + ' ' + ' ' + ' ' + " " + ' ' + ' ' + "
" + '
' + ' " + ' " + '

' + ' " + ' " + "
" + '
' + " " + ' ' + ' ' + ' ' + " " + ' ' + ' ' + "
" //+'
' + ' ' + //'" + ' " + "
" + "
").insertBefore(this.element); this.elements = { originalSelect: this.element, box1: $(".box1", this.container), box2: $(".box2", this.container), filterInput1: $(".box1 .filter", this.container), filterInput2: $(".box2 .filter", this.container), filterClear1: $(".box1 .clear1", this.container), filterClear2: $(".box2 .clear2", this.container), label1: $(".box1 > label", this.container), label2: $(".box2 > label", this.container), info1: $(".box1 .info", this.container), info2: $(".box2 .info", this.container), select1: $(".box1 select", this.container), select2: $(".box2 select", this.container), moveButton: $(".btn-box .move", this.container), removeButton: $(".btn-box .remove", this.container), moveAllButton: $(".btn-box .moveall", this.container), removeAllButton: $(".btn-box .removeall", this.container), upButton: $(".settingUp-btns .upBtn", this.container), downButton: $(".settingUp-btns .downBtn", this.container), form: $($(".box1 .filter", this.container)[0].form) }; this.originalSelectName = this.element.attr("name") || ""; var select1Id = "bootstrap-duallistbox-nonselected-list_" + this.originalSelectName, select2Id = "bootstrap-duallistbox-selected-list_" + this.originalSelectName; this.elements.select1.attr("id", select1Id); this.elements.select2.attr("id", select2Id); this.elements.label1.attr("for", select1Id); this.elements.label2.attr("for", select2Id); this.selectedElements = 0; this.elementCount = 0; this.setBootstrap2Compatible(this.settings.bootstrap2Compatible); this.setFilterTextClear(this.settings.filterTextClear); this.setFilterPlaceHolder(this.settings.filterPlaceHolder); this.setMoveSelectedLabel(this.settings.moveSelectedLabel); this.setMoveAllLabel(this.settings.moveAllLabel); this.setRemoveSelectedLabel(this.settings.removeSelectedLabel); this.setRemoveAllLabel(this.settings.removeAllLabel); this.setMoveOnSelect(this.settings.moveOnSelect); this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove); this.setSelectedListLabel(this.settings.selectedListLabel); this.setNonSelectedListLabel(this.settings.nonSelectedListLabel); this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix); this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight); this.setDoubleMove(this.settings.doubleMove); updateSelectionStates(this); this.setShowFilterInputs(this.settings.showFilterInputs); this.setNonSelectedFilter(this.settings.nonSelectedFilter); this.setSelectedFilter(this.settings.selectedFilter); this.setInfoText(this.settings.infoText); this.setInfoTextFiltered(this.settings.infoTextFiltered); this.setInfoTextEmpty(this.settings.infoTextEmpty); this.setFilterOnValues(this.settings.filterOnValues); this.element.hide(); bindEvents(this); refreshSelects(this); return this.element }, setBootstrap2Compatible: function (value, refresh) { this.settings.bootstrap2Compatible = value; if (value) { this.container.removeClass("row").addClass("row-fluid bs2compatible"); this.container.find(".box1, .box2").removeClass("col-md-5"); this.container.find(".btn-box").removeClass("col-md-2"); this.container.find(".clear1, .clear2").removeClass("btn-default btn-xs").addClass("btn-mini"); this.container.find("input, select").removeClass("form-control"); this.container.find(".btn").removeClass("btn-default"); this.container.find(".moveall > i, .move > i").removeClass("glyphicon glyphicon-arrow-right").addClass("icon-arrow-right"); this.container.find(".removeall > i, .remove > i").removeClass("glyphicon glyphicon-arrow-left").addClass("icon-arrow-left"); this.container.find(".upBtn > i").removeClass("glyphicon glyphicon-arrow-up").addClass("icon-arrow-up"); this.container.find(".downBtn > i").removeClass("glyphicon glyphicon-arrow-down").addClass("icon-arrow-down"); } else { this.container.removeClass("row-fluid bs2compatible")//.addClass("row"); //this.container.find(".box1, .box2").addClass("col-md-5"); this.container.find(".box1, .box2").css("width","41%"); //this.container.find(".btn-box").addClass("col-md-2"); this.container.find(".btn-box").css("width", "17%"); this.container.find(".clear1, .clear2").removeClass("btn-mini").addClass("btn-default btn-xs"); this.container.find("input, select").addClass("form-control"); this.container.find(".btn").addClass("btn-default"); this.container.find(".moveall > i, .move > i").removeClass("icon-arrow-right").addClass("glyphicon glyphicon-arrow-right"); this.container.find(".removeall > i, .remove > i").removeClass("icon-arrow-left").addClass("glyphicon glyphicon-arrow-left"); this.container.find(".upBtn > i").removeClass("icon-arrow-up").addClass("glyphicon glyphicon-arrow-up"); this.container.find(".downBtn > i").removeClass("icon-arrow-down").addClass("glyphicon glyphicon-arrow-down"); } if (refresh) { refreshSelects(this) } return this.element }, setFilterTextClear: function (value, refresh) { this.settings.filterTextClear = value; this.elements.filterClear1.html(value); this.elements.filterClear2.html(value); if (refresh) { refreshSelects(this) } return this.element }, setFilterPlaceHolder: function (value, refresh) { this.settings.filterPlaceHolder = value; this.elements.filterInput1.attr("placeholder", value); this.elements.filterInput2.attr("placeholder", value); if (refresh) { refreshSelects(this) } return this.element }, setMoveSelectedLabel: function (value, refresh) { this.settings.moveSelectedLabel = value; this.elements.moveButton.attr("title", value); if (refresh) { refreshSelects(this) } return this.element }, setMoveAllLabel: function (value, refresh) { this.settings.moveAllLabel = value; this.elements.moveAllButton.attr("title", value); if (refresh) { refreshSelects(this) } return this.element }, setRemoveSelectedLabel: function (value, refresh) { this.settings.removeSelectedLabel = value; this.elements.removeButton.attr("title", value); if (refresh) { refreshSelects(this) } return this.element }, setRemoveAllLabel: function (value, refresh) { this.settings.removeAllLabel = value; this.elements.removeAllButton.attr("title", value); if (refresh) { refreshSelects(this) } return this.element }, setMoveOnSelect: function (value, refresh) { if (isBuggyAndroid) { value = true } this.settings.moveOnSelect = value; if (this.settings.moveOnSelect) { this.container.addClass("moveonselect"); var self = this; this.elements.select1.on("change", function () { move(self) }); this.elements.select2.on("change", function () { remove(self) }) } else { this.container.removeClass("moveonselect"); this.elements.select1.off("change"); this.elements.select2.off("change") } if (refresh) { refreshSelects(this) } return this.element }, setDoubleMove: function (value, refresh) { if (isBuggyAndroid) { value = false } this.settings.doubleMove = value; if (this.settings.doubleMove) { var self = this; this.elements.select1.on("dblclick", function () { move(self) }); this.elements.select2.on("dblclick", function () { remove(self) }) } else { this.elements.select1.off("dblclick"); this.elements.select2.off("dblclick") } if (refresh) { refreshSelects(this) } return this.element }, setPreserveSelectionOnMove: function (value, refresh) { if (isBuggyAndroid) { value = false } this.settings.preserveSelectionOnMove = value; if (refresh) { refreshSelects(this) } return this.element }, setSelectedListLabel: function (value, refresh) { this.settings.selectedListLabel = value; if (value) { this.elements.label2.show().html(value) } else { this.elements.label2.hide().html(value) } if (refresh) { refreshSelects(this) } return this.element }, setNonSelectedListLabel: function (value, refresh) { this.settings.nonSelectedListLabel = value; if (value) { this.elements.label1.show().html(value) } else { this.elements.label1.hide().html(value) } if (refresh) { refreshSelects(this) } return this.element }, setHelperSelectNamePostfix: function (value, refresh) { this.settings.helperSelectNamePostfix = value; if (value) { this.elements.select1.attr("name", this.originalSelectName + value + "1"); this.elements.select2.attr("name", this.originalSelectName + value + "2") } else { this.elements.select1.removeAttr("name"); this.elements.select2.removeAttr("name") } if (refresh) { refreshSelects(this) } return this.element }, setSelectOrMinimalHeight: function (value, refresh) { this.settings.selectorMinimalHeight = value; var height = this.element.height(); if (this.element.height() < value) { height = value } this.elements.select1.height(height); this.elements.select2.height(height); if (refresh) { refreshSelects(this) } return this.element }, setShowFilterInputs: function (value, refresh) { if (!value) { this.setNonSelectedFilter(""); this.setSelectedFilter(""); refreshSelects(this); this.elements.filterInput1.hide(); this.elements.filterInput2.hide() } else { this.elements.filterInput1.show(); this.elements.filterInput2.show() } this.settings.showFilterInputs = value; if (refresh) { refreshSelects(this) } return this.element }, setNonSelectedFilter: function (value, refresh) { if (this.settings.showFilterInputs) { this.settings.nonSelectedFilter = value; this.elements.filterInput1.val(value); if (refresh) { refreshSelects(this) } return this.element } }, setSelectedFilter: function (value, refresh) { if (this.settings.showFilterInputs) { this.settings.selectedFilter = value; this.elements.filterInput2.val(value); if (refresh) { refreshSelects(this) } return this.element } }, setInfoText: function (value, refresh) { this.settings.infoText = value; if (refresh) { refreshSelects(this) } return this.element }, setInfoTextFiltered: function (value, refresh) { this.settings.infoTextFiltered = value; if (refresh) { refreshSelects(this) } return this.element }, setInfoTextEmpty: function (value, refresh) { this.settings.infoTextEmpty = value; if (refresh) { refreshSelects(this) } return this.element }, setFilterOnValues: function (value, refresh) { this.settings.filterOnValues = value; if (refresh) { refreshSelects(this) } return this.element }, getContainer: function () { return this.container }, refresh: function (mustClearSelections) { updateSelectionStates(this); if (!mustClearSelections) { saveSelections(this, 1); saveSelections(this, 2) } else { clearSelections(this) } refreshSelects(this) }, destroy: function () { this.container.remove(); this.element.show(); $.data(this, "plugin_" + pluginName, null); return this.element } }; $.fn[pluginName] = function (options) { var args = arguments; if (options === undefined || typeof options === "object") { return this.each(function () { if (!$(this).is("select")) { $(this).find("select").each(function (index, item) { $(item).bootstrapDualListbox(options) }) } else { if (!$.data(this, "plugin_" + pluginName)) { $.data(this, "plugin_" + pluginName, new BootstrapDualListbox(this, options)) } } }) } else { if (typeof options === "string" && options[0] !== "_" && options !== "init") { var returns; this.each(function () { var instance = $.data(this, "plugin_" + pluginName); if (instance instanceof BootstrapDualListbox && typeof instance[options] === "function") { returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1)) } }); return returns !== undefined ? returns : this } } } })(jQuery, window, document); (function (root, factory) { if (typeof exports === "object") { module.exports = factory(root, require("jquery")) } else { if (typeof define === "function" && define.amd) { define(["jquery"], function (jQuery) { return factory(root, jQuery) }) } else { factory(root, root.jQuery) } } }(this, function (window, $, undefined) { $.fn.doublebox = function (options) { var box = this.bootstrapDualListbox(options); var items = ""; box.selectElement = function () { if (options.nonSelectedList != null) { for (var i in options.nonSelectedList) { if (options.nonSelectedList.hasOwnProperty(i)) { items += "" } } } if (options.selectedList != null) { for (var i in options.selectedList) { if (options.selectedList.hasOwnProperty(i)) { items += "" } } } box.append(items); box.bootstrapDualListbox("refresh") }; box.getSelectedOptions = function () { var items = $("#bootstrap-duallistbox-selected-list_doublebox>option").map(function () { return $(this).val() }).get().join(","); return items }; box.selectElement(); return box; } }));