123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- /*
- * @license
- *
- * Multiselect v2.5.2
- * http://crlcu.github.io/multiselect/
- *
- * Copyright (c) 2016-2018 Adrian Crisan
- * Licensed under the MIT license (https://github.com/crlcu/multiselect/blob/master/LICENSE)
- */
- if (typeof jQuery === 'undefined') {
- throw new Error('multiselect requires jQuery');
- }
- ;(function ($) {
- 'use strict';
- var version = $.fn.jquery.split(' ')[0].split('.');
- if (version[0] < 2 && version[1] < 7) {
- throw new Error('multiselect requires jQuery version 1.7 or higher');
- }
- })(jQuery);
- ;(function (factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module depending on jQuery.
- define(['jquery'], factory);
- } else {
- // No AMD. Register plugin with global jQuery object.
- factory(jQuery);
- }
- }(function ($) {
- 'use strict';
- var Multiselect = (function($) {
- /** Multiselect object constructor
- *
- * @class Multiselect
- * @constructor
- **/
- function Multiselect( $select, settings ) {
- var id = $select.prop('id');
- this.$left = $select;
- this.$right = $( settings.right ).length ? $( settings.right ) : $('#' + id + '_to');
- this.actions = {
- $leftAll: $( settings.leftAll ).length ? $( settings.leftAll ) : $('#' + id + '_leftAll'),
- $rightAll: $( settings.rightAll ).length ? $( settings.rightAll ) : $('#' + id + '_rightAll'),
- $leftSelected: $( settings.leftSelected ).length ? $( settings.leftSelected ) : $('#' + id + '_leftSelected'),
- $rightSelected: $( settings.rightSelected ).length ? $( settings.rightSelected ) : $('#' + id + '_rightSelected'),
- $undo: $( settings.undo ).length ? $( settings.undo ) : $('#' + id + '_undo'),
- $redo: $( settings.redo ).length ? $( settings.redo ) : $('#' + id + '_redo'),
- $moveUp: $( settings.moveUp ).length ? $( settings.moveUp ) : $('#' + id + '_move_up'),
- $moveDown: $( settings.moveDown ).length ? $( settings.moveDown ) : $('#' + id + '_move_down')
- };
- delete settings.leftAll;
- delete settings.leftSelected;
- delete settings.right;
- delete settings.rightAll;
- delete settings.rightSelected;
- delete settings.undo;
- delete settings.redo;
- delete settings.moveUp;
- delete settings.moveDown;
- this.options = {
- keepRenderingSort: settings.keepRenderingSort,
- submitAllLeft: settings.submitAllLeft !== undefined ? settings.submitAllLeft : true,
- submitAllRight: settings.submitAllRight !== undefined ? settings.submitAllRight : true,
- search: settings.search,
- ignoreDisabled: settings.ignoreDisabled !== undefined ? settings.ignoreDisabled : false,
- matchOptgroupBy: settings.matchOptgroupBy !== undefined ? settings.matchOptgroupBy : 'label'
- };
- delete settings.keepRenderingSort, settings.submitAllLeft, settings.submitAllRight, settings.search, settings.ignoreDisabled, settings.matchOptgroupBy;
- this.callbacks = settings;
- if ( typeof this.callbacks.sort == 'function' ) {
- var sort = this.callbacks.sort;
- this.callbacks.sort = {
- left: sort,
- right: sort,
- };
- }
- this.init();
- }
- Multiselect.prototype = {
- init: function() {
- var self = this;
- self.undoStack = [];
- self.redoStack = [];
- if (self.options.keepRenderingSort) {
- self.skipInitSort = true;
- if (self.callbacks.sort !== false) {
- self.callbacks.sort = {
- left: function(a, b) {
- return $(a).data('position') > $(b).data('position') ? 1 : -1;
- },
- right: function(a, b) {
- return $(a).data('position') > $(b).data('position') ? 1 : -1;
- },
- };
- }
- self.$left.attachIndex();
- self.$right.each(function(i, select) {
- $(select).attachIndex();
- });
- }
- if ( typeof self.callbacks.startUp == 'function' ) {
- self.callbacks.startUp( self.$left, self.$right );
- }
- if ( !self.skipInitSort ) {
- if ( typeof self.callbacks.sort.left == 'function' ) {
- self.$left.mSort(self.callbacks.sort.left);
- }
- if ( typeof self.callbacks.sort.right == 'function' ) {
- self.$right.each(function(i, select) {
- $(select).mSort(self.callbacks.sort.right);
- });
- }
- }
- // Append left filter
- if (self.options.search && self.options.search.left) {
- self.options.search.$left = $(self.options.search.left);
- self.$left.before(self.options.search.$left);
- }
- // Append right filter
- if (self.options.search && self.options.search.right) {
- self.options.search.$right = $(self.options.search.right);
- self.$right.before($(self.options.search.$right));
- }
- // Initialize events
- self.events();
- if ( typeof self.callbacks.afterInit == 'function' ) {
- self.callbacks.afterInit();
- }
- },
- events: function() {
- var self = this;
- // Attach event to left filter
- if (self.options.search && self.options.search.$left) {
- self.options.search.$left.on('keyup', function(e) {
- if (self.callbacks.fireSearch(this.value)) {
- var $toShow = self.$left.find('option:search("' + this.value + '")').mShow();
- var $toHide = self.$left.find('option:not(:search("' + this.value + '"))').mHide();
- var $grpHide = self.$left.find('option').closest('optgroup').mHide();
- var $grpShow = self.$left.find('option:not(.hidden)').parent('optgroup').mShow();
- } else {
- self.$left.find('option, optgroup').mShow();
- }
- });
- }
- // Attach event to right filter
- if (self.options.search && self.options.search.$right) {
- self.options.search.$right.on('keyup', function(e) {
- if (self.callbacks.fireSearch(this.value)) {
- var $toShow = self.$right.find('option:search("' + this.value + '")').mShow();
- var $toHide = self.$right.find('option:not(:search("' + this.value + '"))').mHide();
- var $grpHide = self.$right.find('option').closest('optgroup').mHide();
- var $grpShow = self.$right.find('option:not(.hidden)').parent('optgroup').mShow();
- } else {
- self.$right.find('option, optgroup').mShow();
- }
- });
- }
- // Select all the options from left and right side when submiting the parent form
- self.$right.closest('form').on('submit', function(e) {
- if (self.options.search) {
- // Clear left search input
- if (self.options.search.$left) {
- self.options.search.$left.val('').trigger('keyup');
- }
- // Clear right search input
- if (self.options.search.$right) {
- self.options.search.$right.val('').trigger('keyup');
- }
- }
- self.$left.find('option').prop('selected', self.options.submitAllLeft);
- self.$right.find('option').prop('selected', self.options.submitAllRight);
- });
- // Attach event for double clicking on options from left side
- self.$left.on('dblclick', 'option', function(e) {
- e.preventDefault();
- var $options = self.$left.find('option:selected');
- if ( $options.length ) {
- self.moveToRight($options, e);
- }
- });
- // Attach event for clicking on optgroup's from left side
- self.$left.on('click', 'optgroup', function(e) {
- if ($(e.target).prop('tagName') == 'OPTGROUP') {
- $(this)
- .children()
- .prop('selected', true);
- }
- });
- // Attach event for pushing ENTER on options from left side
- self.$left.on('keypress', function(e) {
- if (e.keyCode === 13) {
- e.preventDefault();
- var $options = self.$left.find('option:selected');
- if ( $options.length ) {
- self.moveToRight($options, e);
- }
- }
- });
- // Attach event for double clicking on options from right side
- self.$right.on('dblclick', 'option', function(e) {
- e.preventDefault();
- var $options = self.$right.find('option:selected');
- if ( $options.length ) {
- self.moveToLeft($options, e);
- }
- });
- // Attach event for clicking on optgroup's from right side
- self.$right.on('click', 'optgroup', function(e) {
- if ($(e.target).prop('tagName') == 'OPTGROUP') {
- $(this)
- .children()
- .prop('selected', true);
- }
- });
- // Attach event for pushing BACKSPACE or DEL on options from right side
- self.$right.on('keydown', function(e) {
- if (e.keyCode === 8 || e.keyCode === 46) {
- e.preventDefault();
- var $options = self.$right.find('option:selected');
- if ( $options.length ) {
- self.moveToLeft($options, e);
- }
- }
- });
- // dblclick support for IE
- if ( navigator.userAgent.match(/MSIE/i) || navigator.userAgent.indexOf('Trident/') > 0 || navigator.userAgent.indexOf('Edge/') > 0) {
- self.$left.dblclick(function(e) {
- self.actions.$rightSelected.trigger('click');
- });
- self.$right.dblclick(function(e) {
- self.actions.$leftSelected.trigger('click');
- });
- }
- self.actions.$rightSelected.on('click', function(e) {
- e.preventDefault();
- var $options = self.$left.find('option:selected');
- if ( $options.length ) {
- self.moveToRight($options, e);
- }
- $(this).blur();
- });
- self.actions.$leftSelected.on('click', function(e) {
- e.preventDefault();
- var $options = self.$right.find('option:selected');
- if ( $options.length ) {
- self.moveToLeft($options, e);
- }
- $(this).blur();
- });
- self.actions.$rightAll.on('click', function(e) {
- e.preventDefault();
- var $options = self.$left.children(':not(span):not(.hidden)');
- if ( $options.length ) {
- self.moveToRight($options, e);
- }
- $(this).blur();
- });
- self.actions.$leftAll.on('click', function(e) {
- e.preventDefault();
- var $options = self.$right.children(':not(span):not(.hidden)');
- if ( $options.length ) {
- self.moveToLeft($options, e);
- }
- $(this).blur();
- });
- self.actions.$undo.on('click', function(e) {
- e.preventDefault();
- self.undo(e);
- });
- self.actions.$redo.on('click', function(e) {
- e.preventDefault();
- self.redo(e);
- });
- self.actions.$moveUp.on('click', function(e) {
- e.preventDefault();
- var $options = self.$right.find(':selected:not(span):not(.hidden)');
- if ( $options.length ) {
- self.moveUp($options, e);
- }
- $(this).blur();
- });
- self.actions.$moveDown.on('click', function(e) {
- e.preventDefault();
- var $options = self.$right.find(':selected:not(span):not(.hidden)');
- if ( $options.length ) {
- self.moveDown($options, e);
- }
- $(this).blur();
- });
- },
- moveToRight: function( $options, event, silent, skipStack ) {
- var self = this;
- if ( typeof self.callbacks.moveToRight == 'function' ) {
- return self.callbacks.moveToRight( self, $options, event, silent, skipStack );
- }
- if ( typeof self.callbacks.beforeMoveToRight == 'function' && !silent ) {
- if ( !self.callbacks.beforeMoveToRight( self.$left, self.$right, $options ) ) {
- return false;
- }
- }
- self.moveFromAtoB(self.$left, self.$right, $options, event, silent, skipStack);
- if ( !skipStack ) {
- self.undoStack.push(['right', $options ]);
- self.redoStack = [];
- }
- if ( typeof self.callbacks.sort.right == 'function' && !silent && !self.doNotSortRight ) {
- self.$right.mSort(self.callbacks.sort.right);
- }
- if ( typeof self.callbacks.afterMoveToRight == 'function' && !silent ) {
- self.callbacks.afterMoveToRight( self.$left, self.$right, $options );
- }
- return self;
- },
- moveToLeft: function( $options, event, silent, skipStack ) {
- var self = this;
- if ( typeof self.callbacks.moveToLeft == 'function' ) {
- return self.callbacks.moveToLeft( self, $options, event, silent, skipStack );
- }
- if ( typeof self.callbacks.beforeMoveToLeft == 'function' && !silent ) {
- if ( !self.callbacks.beforeMoveToLeft( self.$left, self.$right, $options ) ) {
- return false;
- }
- }
- self.moveFromAtoB(self.$right, self.$left, $options, event, silent, skipStack);
- if ( !skipStack ) {
- self.undoStack.push(['left', $options ]);
- self.redoStack = [];
- }
- if ( typeof self.callbacks.sort.left == 'function' && !silent ) {
- self.$left.mSort(self.callbacks.sort.left);
- }
- if ( typeof self.callbacks.afterMoveToLeft == 'function' && !silent ) {
- self.callbacks.afterMoveToLeft( self.$left, self.$right, $options );
- }
- return self;
- },
- moveFromAtoB: function( $source, $destination, $options, event, silent, skipStack ) {
- var self = this;
- if ( typeof self.callbacks.moveFromAtoB == 'function' ) {
- return self.callbacks.moveFromAtoB(self, $source, $destination, $options, event, silent, skipStack);
- }
- $options.each(function(index, option) {
- var $option = $(option);
- if (self.options.ignoreDisabled && $option.is(':disabled')) {
- return true;
- }
- if ($option.is('optgroup') || $option.parent().is('optgroup')) {
- var $sourceGroup = $option.is('optgroup') ? $option : $option.parent();
- var optgroupSelector = 'optgroup[' + self.options.matchOptgroupBy + '="' + $sourceGroup.prop(self.options.matchOptgroupBy) + '"]';
- var $destinationGroup = $destination.find(optgroupSelector);
- if (!$destinationGroup.length) {
- $destinationGroup = $sourceGroup.clone(true);
- $destinationGroup.empty();
- $destination.move($destinationGroup);
- }
- if ($option.is('optgroup')) {
- $destinationGroup.move($option.find('option'));
- } else {
- $destinationGroup.move($option);
- }
- $sourceGroup.removeIfEmpty();
- } else {
- $destination.move($option);
- }
- });
- return self;
- },
- moveUp: function($options) {
- var self = this;
- if ( typeof self.callbacks.beforeMoveUp == 'function' ) {
- if ( !self.callbacks.beforeMoveUp( $options ) ) {
- return false;
- }
- }
- $options.first().prev().before($options);
- if ( typeof self.callbacks.afterMoveUp == 'function' ) {
- self.callbacks.afterMoveUp( $options );
- }
- },
- moveDown: function($options) {
- var self = this;
- if ( typeof self.callbacks.beforeMoveDown == 'function' ) {
- if ( !self.callbacks.beforeMoveDown( $options ) ) {
- return false;
- }
- }
- $options.last().next().after($options);
- if ( typeof self.callbacks.afterMoveDown == 'function' ) {
- self.callbacks.afterMoveDown( $options );
- }
- },
- undo: function(event) {
- var self = this;
- var last = self.undoStack.pop();
- if ( last ) {
- self.redoStack.push(last);
- switch(last[0]) {
- case 'left':
- self.moveToRight(last[1], event, false, true);
- break;
- case 'right':
- self.moveToLeft(last[1], event, false, true);
- break;
- }
- }
- },
- redo: function(event) {
- var self = this;
- var last = self.redoStack.pop();
- if ( last ) {
- self.undoStack.push(last);
- switch(last[0]) {
- case 'left':
- self.moveToLeft(last[1], event, false, true);
- break;
- case 'right':
- self.moveToRight(last[1], event, false, true);
- break;
- }
- }
- }
- }
- return Multiselect;
- })($);
- $.multiselect = {
- defaults: {
- /** will be executed once - remove from $left all options that are already in $right
- *
- * @method startUp
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- **/
- startUp: function( $left, $right ) {
- $right.find('option').each(function(index, rightOption) {
- if ($(rightOption).parent().prop('tagName') == 'OPTGROUP') {
- var optgroupSelector = 'optgroup[label="' + $(rightOption).parent().attr('label') + '"]';
- $left.find(optgroupSelector + ' option[value="' + rightOption.value + '"]').each(function(index, leftOption) {
- leftOption.remove();
- });
- $left.find(optgroupSelector).removeIfEmpty();
- } else {
- var $option = $left.find('option[value="' + rightOption.value + '"]');
- $option.remove();
- }
- });
- },
- /** will be executed after initialize plugin
- *
- * @method afterInit
- *
- * @default true
- * @return {boolean}
- **/
- afterInit: function(){ return true; },
- /** will be executed each time before moving option[s] to right
- *
- * IMPORTANT : this method must return boolean value
- * true : continue to moveToRight method
- * false : stop
- *
- * @method beforeMoveToRight
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- *
- * @default true
- * @return {boolean}
- **/
- beforeMoveToRight: function($left, $right, $options) { return true; },
- /* will be executed each time after moving option[s] to right
- *
- * @method afterMoveToRight
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- **/
- afterMoveToRight: function($left, $right, $options) {},
- /** will be executed each time before moving option[s] to left
- *
- * IMPORTANT : this method must return boolean value
- * true : continue to moveToRight method
- * false : stop
- *
- * @method beforeMoveToLeft
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- *
- * @default true
- * @return {boolean}
- **/
- beforeMoveToLeft: function($left, $right, $options) { return true; },
- /* will be executed each time after moving option[s] to left
- *
- * @method afterMoveToLeft
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- **/
- afterMoveToLeft: function($left, $right, $options) {},
- /** will be executed each time before moving option[s] up
- *
- * IMPORTANT : this method must return boolean value
- * true : continue to moveUp method
- * false : stop
- *
- * @method beforeMoveUp
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- *
- * @default true
- * @return {boolean}
- **/
- beforeMoveUp: function($options) { return true; },
- /* will be executed each time after moving option[s] up
- *
- * @method afterMoveUp
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- **/
- afterMoveUp: function($options) {},
- /** will be executed each time before moving option[s] down
- *
- * IMPORTANT : this method must return boolean value
- * true : continue to moveUp method
- * false : stop
- *
- * @method beforeMoveDown
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- *
- * @default true
- * @return {boolean}
- **/
- beforeMoveDown: function($options) { return true; },
- /* will be executed each time after moving option[s] down
- *
- * @method afterMoveUp
- * @attribute $left jQuery object
- * @attribute $right jQuery object
- * @attribute $options HTML object (the option[s] which was selected to be moved)
- **/
- afterMoveDown: function($options) {},
- /** sort options by option text
- *
- * @method sort
- * @attribute a HTML option
- * @attribute b HTML option
- *
- * @return 1/-1
- **/
- sort: function(a, b) {
- if (a.innerHTML == 'NA') {
- return 1;
- } else if (b.innerHTML == 'NA') {
- return -1;
- }
- return (a.innerHTML > b.innerHTML) ? 1 : -1;
- },
- /* will tell if the search can start
- *
- * @method fireSearch
- * @attribute value String
- *
- * @return {boolean}
- **/
- fireSearch: function(value) {
- return value.length > 1;
- }
- }
- };
- var ua = window.navigator.userAgent;
- var isIE = (ua.indexOf("MSIE ") + ua.indexOf("Trident/") + ua.indexOf("Edge/")) > -3;
- var isSafari = ua.toLowerCase().indexOf("safari") > -1;
- var isFirefox = ua.toLowerCase().indexOf("firefox") > -1;
- $.fn.multiselect = function( options ) {
- return this.each(function() {
- var $this = $(this),
- data = $this.data('crlcu.multiselect'),
- settings = $.extend({}, $.multiselect.defaults, $this.data(), (typeof options === 'object' && options));
- if (!data) {
- $this.data('crlcu.multiselect', (data = new Multiselect($this, settings)));
- }
- });
- };
- // append options
- // then set the selected attribute to false
- $.fn.move = function( $options ) {
- this
- .append($options)
- .find('option')
- .prop('selected', false);
- return this;
- };
- $.fn.removeIfEmpty = function() {
- if (!this.children().length) {
- this.remove();
- }
- return this;
- };
- $.fn.mShow = function() {
- this.removeClass('hidden').show();
- if (isIE || isSafari) {
- this.each(function(index, option) {
- // Remove <span> to make it compatible with IE
- if($(option).parent().is('span')) {
- $(option).parent().replaceWith(option);
- }
- $(option).show();
- });
- }
- if(isFirefox){
- this.attr('disabled', false)
- }
- return this;
- };
- $.fn.mHide = function() {
- this.addClass('hidden').hide();
- if (isIE || isSafari) {
- this.each(function(index, option) {
- // Wrap with <span> to make it compatible with IE
- if(!$(option).parent().is('span')) {
- $(option).wrap('<span>').hide();
- }
- });
- }
- if(isFirefox){
- this.attr('disabled', true)
- }
- return this;
- };
- // sort options then reappend them to the select
- $.fn.mSort = function(callback) {
- this
- .children()
- .sort(callback)
- .appendTo(this);
- this
- .find('optgroup')
- .each(function(i, group) {
- $(group).children()
- .sort(callback)
- .appendTo(group);
- })
- return this;
- };
- // attach index to children
- $.fn.attachIndex = function() {
- this.children().each(function(index, option) {
- var $option = $(option);
- if ($option.is('optgroup')) {
- $option.children().each(function(i, children) {
- $(children).data('position', i);
- });
- }
- $option.data('position', index);
- });
- };
- $.expr[":"].search = function(elem, index, meta) {
- var regex = new RegExp(meta[3].replace(/([^a-zA-Z0-9])/g, "\\$1"), "i");
- return $(elem).text().match(regex);
- }
- }));
|