Browse Source

Update dependencies (#2748)

* @fullcalendar/bootstrap             ^4.4.0  →    ^4.4.2
* @fullcalendar/core                  ^4.4.0  →    ^4.4.2
* @fullcalendar/daygrid               ^4.4.0  →    ^4.4.2
* @fullcalendar/interaction           ^4.4.0  →    ^4.4.2
* @fullcalendar/timegrid              ^4.4.0  →    ^4.4.2
* @ttskch/select2-bootstrap4-theme     ^1.3.2  →   ^1.4.0
* bootstrap4-duallistbox              ^4.0.1  →    ^4.0.2
* datatables.net                    ^1.10.20  →  ^1.10.21
* datatables.net-autofill-bs4         ^2.3.4  →    ^2.3.5
* datatables.net-bs4                ^1.10.20  →  ^1.10.21
* datatables.net-buttons-bs4          ^1.6.1  →    ^1.6.2
* datatables.net-fixedcolumns-bs4     ^3.3.0  →    ^3.3.1
* datatables.net-fixedheader-bs4      ^3.1.6  →    ^3.1.7
* datatables.net-keytable-bs4         ^2.5.1  →    ^2.5.2
* datatables.net-responsive-bs4       ^2.2.3  →    ^2.2.5
* datatables.net-rowgroup-bs4         ^1.1.1  →    ^1.1.2
* datatables.net-rowreorder-bs4       ^1.2.6  →    ^1.2.7
* datatables.net-scroller-bs4         ^2.0.1  →    ^2.0.2
* filterizr                           ^2.2.3  →    ^2.2.4
* flot                                ^4.2.0  →    ^4.2.1
* jquery-validation                  ^1.19.1  →   ^1.19.2
* jszip                               ^3.3.0  →    ^3.4.0
* overlayscrollbars                  ^1.11.0  →   ^1.12.0
* summernote                         ^0.8.16  →   ^0.8.18
* sweetalert2                        ^9.10.8  →   ^9.14.0
XhmikosR 4 years ago
parent
commit
8350264bd2

File diff suppressed because it is too large
+ 165 - 413
package-lock.json


+ 25 - 25
package.json

@@ -67,40 +67,40 @@
   },
   "dependencies": {
     "@fortawesome/fontawesome-free": "^5.13.0",
-    "@fullcalendar/bootstrap": "^4.4.0",
-    "@fullcalendar/core": "^4.4.0",
-    "@fullcalendar/daygrid": "^4.4.0",
-    "@fullcalendar/interaction": "^4.4.0",
-    "@fullcalendar/timegrid": "^4.4.0",
+    "@fullcalendar/bootstrap": "^4.4.2",
+    "@fullcalendar/core": "^4.4.2",
+    "@fullcalendar/daygrid": "^4.4.2",
+    "@fullcalendar/interaction": "^4.4.2",
+    "@fullcalendar/timegrid": "^4.4.2",
     "@lgaitan/pace-progress": "^1.0.7",
     "@sweetalert2/theme-bootstrap-4": "^3.1.4",
-    "@ttskch/select2-bootstrap4-theme": "^1.3.2",
+    "@ttskch/select2-bootstrap4-theme": "^1.4.0",
     "bootstrap": "^4.4.1",
     "bootstrap-colorpicker": "^3.2.0",
     "bootstrap-slider": "^10.6.2",
     "bootstrap-switch": "3.3.4",
-    "bootstrap4-duallistbox": "^4.0.1",
+    "bootstrap4-duallistbox": "^4.0.2",
     "bs-custom-file-input": "^1.3.4",
     "chart.js": "^2.9.3",
-    "datatables.net": "^1.10.20",
-    "datatables.net-autofill-bs4": "^2.3.4",
-    "datatables.net-bs4": "^1.10.20",
-    "datatables.net-buttons-bs4": "^1.6.1",
+    "datatables.net": "^1.10.21",
+    "datatables.net-autofill-bs4": "^2.3.5",
+    "datatables.net-bs4": "^1.10.21",
+    "datatables.net-buttons-bs4": "^1.6.2",
     "datatables.net-colreorder-bs4": "^1.5.2",
-    "datatables.net-fixedcolumns-bs4": "^3.3.0",
-    "datatables.net-fixedheader-bs4": "^3.1.6",
-    "datatables.net-keytable-bs4": "^2.5.1",
-    "datatables.net-responsive-bs4": "^2.2.3",
-    "datatables.net-rowgroup-bs4": "^1.1.1",
-    "datatables.net-rowreorder-bs4": "^1.2.6",
-    "datatables.net-scroller-bs4": "^2.0.1",
+    "datatables.net-fixedcolumns-bs4": "^3.3.1",
+    "datatables.net-fixedheader-bs4": "^3.1.7",
+    "datatables.net-keytable-bs4": "^2.5.2",
+    "datatables.net-responsive-bs4": "^2.2.5",
+    "datatables.net-rowgroup-bs4": "^1.1.2",
+    "datatables.net-rowreorder-bs4": "^1.2.7",
+    "datatables.net-scroller-bs4": "^2.0.2",
     "datatables.net-select-bs4": "^1.3.1",
     "daterangepicker": "^3.1.0",
     "ekko-lightbox": "^5.3.0",
     "fastclick": "^1.0.6",
-    "filterizr": "^2.2.3",
+    "filterizr": "^2.2.4",
     "flag-icon-css": "^3.4.6",
-    "flot": "^4.2.0",
+    "flot": "^4.2.1",
     "fs-extra": "^9.0.0",
     "icheck-bootstrap": "^3.0.1",
     "inputmask": "^5.0.3",
@@ -110,19 +110,19 @@
     "jquery-mapael": "^2.2.0",
     "jquery-mousewheel": "^3.1.13",
     "jquery-ui-dist": "^1.12.1",
-    "jquery-validation": "^1.19.1",
+    "jquery-validation": "^1.19.2",
     "jqvmap-novulnerability": "^1.5.1",
     "jsgrid": "^1.5.3",
-    "jszip": "^3.3.0",
+    "jszip": "^3.4.0",
     "moment": "^2.24.0",
-    "overlayscrollbars": "^1.11.0",
+    "overlayscrollbars": "^1.12.0",
     "pdfmake": "^0.1.65",
     "popper.js": "^1.16.1",
     "raphael": "^2.3.0",
     "select2": "^4.0.13",
     "sparklines": "^1.2.0",
-    "summernote": "^0.8.16",
-    "sweetalert2": "^9.10.8",
+    "summernote": "^0.8.18",
+    "sweetalert2": "^9.14.0",
     "tempusdominus-bootstrap-4": "^5.1.2",
     "toastr": "^2.1.4"
   },

+ 80 - 80
plugins/bootstrap4-duallistbox/bootstrap-duallistbox.css

@@ -1,87 +1,87 @@
 /*
- *  Bootstrap Duallistbox - v4.0.1
+ *  Bootstrap Duallistbox - v4.0.2
  *  A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
  *  http://www.virtuosoft.eu/code/bootstrap-duallistbox/
  *
  *  Made by István Ujj-Mészáros
  *  Under Apache License v2.0 License
  */
-.bootstrap-duallistbox-container .buttons {
-  width: 100%;
-  margin-bottom: -1px;
-}
-
-.bootstrap-duallistbox-container label {
-  display: block;
-}
-
-.bootstrap-duallistbox-container .info {
-  display: inline-block;
-  margin-bottom: 5px;
-  font-size: 11px;
-}
-
-.bootstrap-duallistbox-container .clear1,
-.bootstrap-duallistbox-container .clear2 {
-  display: none;
-  font-size: 10px;
-}
-
-.bootstrap-duallistbox-container .box1.filtered .clear1,
-.bootstrap-duallistbox-container .box2.filtered .clear2 {
-  display: inline-block;
-}
-
-.bootstrap-duallistbox-container .move,
-.bootstrap-duallistbox-container .remove {
-  width: 50%;
-  box-sizing: content-box;
-}
-
-.bootstrap-duallistbox-container .btn-group .btn {
-  border-bottom-left-radius: 0;
-  border-bottom-right-radius: 0;
-}
-.bootstrap-duallistbox-container:not(.moveonselect) select {
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-}
-.bootstrap-duallistbox-container .moveall,
-.bootstrap-duallistbox-container .removeall {
-  width: 50%;
-  box-sizing: content-box;
-}
-
-.bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn {
-  margin-left: 0;
-}
-
-.bootstrap-duallistbox-container select {
-  width: 100%;
-  height: 300px;
-  padding: 0;
-}
-
-.bootstrap-duallistbox-container .filter {
-  display: inline-block;
-  width: 100%;
-  height: 31px;
-  margin: 0 0 5px 0;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-}
-
-.bootstrap-duallistbox-container .filter.placeholder {
-  color: #aaa;
-}
-
-.bootstrap-duallistbox-container.moveonselect .move,
-.bootstrap-duallistbox-container.moveonselect .remove {
-  display:none;
-}
-
-.bootstrap-duallistbox-container.moveonselect .moveall,
-.bootstrap-duallistbox-container.moveonselect .removeall {
-  width: 100%;
-}
+.bootstrap-duallistbox-container .buttons {
+  width: 100%;
+  margin-bottom: -1px;
+}
+
+.bootstrap-duallistbox-container label {
+  display: block;
+}
+
+.bootstrap-duallistbox-container .info {
+  display: inline-block;
+  margin-bottom: 5px;
+  font-size: 11px;
+}
+
+.bootstrap-duallistbox-container .clear1,
+.bootstrap-duallistbox-container .clear2 {
+  display: none;
+  font-size: 10px;
+}
+
+.bootstrap-duallistbox-container .box1.filtered .clear1,
+.bootstrap-duallistbox-container .box2.filtered .clear2 {
+  display: inline-block;
+}
+
+.bootstrap-duallistbox-container .move,
+.bootstrap-duallistbox-container .remove {
+  width: 50%;
+  box-sizing: content-box;
+}
+
+.bootstrap-duallistbox-container .btn-group .btn {
+  border-bottom-left-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.bootstrap-duallistbox-container:not(.moveonselect) select {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.bootstrap-duallistbox-container .moveall,
+.bootstrap-duallistbox-container .removeall {
+  width: 50%;
+  box-sizing: content-box;
+}
+
+.bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn {
+  margin-left: 0;
+}
+
+.bootstrap-duallistbox-container select {
+  width: 100%;
+  height: 300px;
+  padding: 0;
+}
+
+.bootstrap-duallistbox-container .filter {
+  display: inline-block;
+  width: 100%;
+  height: 31px;
+  margin: 0 0 5px 0;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+.bootstrap-duallistbox-container .filter.placeholder {
+  color: #aaa;
+}
+
+.bootstrap-duallistbox-container.moveonselect .move,
+.bootstrap-duallistbox-container.moveonselect .remove {
+  display:none;
+}
+
+.bootstrap-duallistbox-container.moveonselect .moveall,
+.bootstrap-duallistbox-container.moveonselect .removeall {
+  width: 100%;
+}

+ 886 - 883
plugins/bootstrap4-duallistbox/jquery.bootstrap-duallistbox.js

@@ -1,890 +1,893 @@
 /*
- *  Bootstrap Duallistbox - v4.0.1
+ *  Bootstrap Duallistbox - v4.0.2
  *  A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
  *  http://www.virtuosoft.eu/code/bootstrap-duallistbox/
  *
  *  Made by István Ujj-Mészáros
  *  Under Apache License v2.0 License
  */
-(function(factory) {
-  if (typeof define === 'function' && define.amd) {
-    define(['jquery'], factory);
-  } else if (typeof module === 'object' && module.exports) {
-    module.exports = function(root, jQuery) {
-      if (jQuery === undefined) {
-        if (typeof window !== 'undefined') {
-          jQuery = require('jquery');
-        }
-        else {
-          jQuery = require('jquery')(root);
-        }
-      }
-      factory(jQuery);
-      return jQuery;
-    };
-  } else {
-    factory(jQuery);
-  }
-}(function($) {
-  // Create the defaults once
-  var pluginName = 'bootstrapDualListbox',
-    defaults = {
-      filterTextClear: 'show all',
-      filterPlaceHolder: 'Filter',
-      moveSelectedLabel: 'Move selected',
-      moveAllLabel: 'Move all',
-      removeSelectedLabel: 'Remove selected',
-      removeAllLabel: 'Remove all',
-      moveOnSelect: true,                                                                 // true/false (forced true on androids, see the comment later)
-      moveOnDoubleClick: true,                                                            // true/false (forced false on androids, cause moveOnSelect is forced to true)
-      preserveSelectionOnMove: false,                                                     // 'all' / 'moved' / false
-      selectedListLabel: false,                                                           // 'string', false
-      nonSelectedListLabel: false,                                                        // 'string', false
-      helperSelectNamePostfix: '_helper',                                                 // 'string_of_postfix' / false
-      selectorMinimalHeight: 100,
-      showFilterInputs: true,                                                             // whether to show filter inputs
-      nonSelectedFilter: '',                                                              // string, filter the non selected options
-      selectedFilter: '',                                                                 // string, filter the selected options
-      infoText: 'Showing all {0}',                                                        // text when all options are visible / false for no info text
-      infoTextFiltered: '<span class="badge badge-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
-      infoTextEmpty: 'Empty list',                                                        // when there are no options present in the list
-      filterOnValues: false,                                                              // filter by selector's values, boolean
-      sortByInputOrder: false,
-      eventMoveOverride: false,                                                           // boolean, allows user to unbind default event behaviour and run their own instead
-      eventMoveAllOverride: false,                                                        // boolean, allows user to unbind default event behaviour and run their own instead
-      eventRemoveOverride: false,                                                         // boolean, allows user to unbind default event behaviour and run their own instead
-      eventRemoveAllOverride: false,                                                      // boolean, allows user to unbind default event behaviour and run their own instead
-      btnClass: 'btn-outline-secondary',                                                  // sets the button style class for all the buttons
-      btnMoveText: '&gt;',                                                                // string, sets the text for the "Move" button
-      btnRemoveText: '&lt;',                                                              // string, sets the text for the "Remove" button
-      btnMoveAllText: '&gt;&gt;',                                                         // string, sets the text for the "Move All" button
-      btnRemoveAllText: '&lt;&lt;'                                                        // string, sets the text for the "Remove All" button
-    },
-    // Selections are invisible on android if the containing select is styled with CSS
-    // http://code.google.com/p/android/issues/detail?id=16922
-    isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
-
-  // The actual plugin constructor
-  function BootstrapDualListbox(element, options) {
-    this.element = $(element);
-    // jQuery has an extend method which merges the contents of two or
-    // more objects, storing the result in the first object. The first object
-    // is generally empty as we don't want to alter the default options for
-    // future instances of the plugin
-    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);
-        if(selected){
-          $item.attr('data-sortindex', dualListbox.sortIndex);
-          dualListbox.sortIndex++;
-        } else {
-          $item.removeAttr('data-sortindex');
-        }
-      }
-    });
-  }
-
-  function formatString(s, args) {
-    console.log(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 {
-        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,
-      allOptions = dualListbox.element.find('option'),
-      options = dualListbox.element;
-
-    if (selectIndex === 1) {
-      options = allOptions.not(':selected');
-    } else  {
-      options = options.find('option:selected');
-    }
-
-    try {
-      regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi');
-    }
-    catch(e) {
-      // a regex to match nothing
-      regex = new RegExp('/a^/', 'gi');
-    }
-
-    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')));
-      }
-      allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
-    });
-
-    refreshInfo(dualListbox);
-  }
-
-  function saveSelections(dualListbox, selectIndex) {
-    var options = dualListbox.element.find('option');
-    dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
-      var $item = $(item);
-      options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));
-    });
-  }
-
-  function sortOptionsByInputOrder(select){
-    var selectopt = select.children('option');
-
-    selectopt.sort(function(a,b){
-      var an = parseInt(a.getAttribute('data-sortindex')),
-          bn = parseInt(b.getAttribute('data-sortindex'));
-
-          if(an > bn) {
-             return 1;
-          }
-          if(an < bn) {
-            return -1;
-          }
-          return 0;
-    });
-
-    selectopt.detach().appendTo(select);
-  }
-
-  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);
-    if(dualListbox.settings.sortByInputOrder){
-        sortOptionsByInputOrder(dualListbox.elements.select2);
-    } else {
-        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);
-    if(dualListbox.settings.sortByInputOrder){
-        sortOptionsByInputOrder(dualListbox.elements.select2);
-    }
-  }
-
-  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').each(function(index, item) {
-      var $item = $(item);
-      if (!$item.data('filtered1')) {
-        $item.prop('selected', true);
-        $item.attr('data-sortindex', dualListbox.sortIndex);
-        dualListbox.sortIndex++;
-      }
-    });
-
-    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);
-        $item.removeAttr('data-sortindex');
-      }
-    });
-
-    refreshSelects(dualListbox);
-    triggerChangeEvent(dualListbox);
-  }
-
-  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);
-    });
-
-    if (dualListbox.settings.eventMoveOverride === false) {
-      dualListbox.elements.moveButton.on('click', function() {
-        move(dualListbox);
-      });
-    }
-
-    if (dualListbox.settings.eventMoveAllOverride === false) {
-      dualListbox.elements.moveAllButton.on('click', function() {
-        moveAll(dualListbox);
-      });
-    }
-
-    if (dualListbox.settings.eventRemoveOverride === false) {
-      dualListbox.elements.removeButton.on('click', function() {
-        remove(dualListbox);
-      });
-    }
-
-    if (dualListbox.settings.eventRemoveAllOverride === false) {
-      dualListbox.elements.removeAllButton.on('click', function() {
-        removeAll(dualListbox);
-      });
-    }
-
-    dualListbox.elements.filterInput1.on('change keyup', function() {
-      filter(dualListbox, 1);
-    });
-
-    dualListbox.elements.filterInput2.on('change keyup', function() {
-      filter(dualListbox, 2);
-    });
-  }
-
-  BootstrapDualListbox.prototype = {
-    init: function () {
-      // Add the custom HTML template
-      this.container = $('' +
-        '<div class="bootstrap-duallistbox-container row">' +
-        ' <div class="box1 col-md-6">' +
-        '   <label></label>' +
-        '   <span class="info-container">' +
-        '     <span class="info"></span>' +
-        '     <button type="button" class="btn btn-sm clear1" style="float:right!important;"></button>' +
-        '   </span>' +
-        '   <input class="form-control filter" type="text">' +
-        '   <div class="btn-group buttons">' +
-        '     <button type="button" class="btn moveall"></button>' +
-        '     <button type="button" class="btn move"></button>' +
-        '   </div>' +
-        '   <select multiple="multiple"></select>' +
-        ' </div>' +
-        ' <div class="box2 col-md-6">' +
-        '   <label></label>' +
-        '   <span class="info-container">' +
-        '     <span class="info"></span>' +
-        '     <button type="button" class="btn btn-sm clear2" style="float:right!important;"></button>' +
-        '   </span>' +
-        '   <input class="form-control filter" type="text">' +
-        '   <div class="btn-group buttons">' +
-        '     <button type="button" class="btn remove"></button>' +
-        '     <button type="button" class="btn removeall"></button>' +
-        '   </div>' +
-        '   <select multiple="multiple"></select>' +
-        ' </div>' +
-        '</div>')
-        .insertBefore(this.element);
-
-      // Cache the inner elements
-      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: $('.box1 .move', this.container),
-        removeButton: $('.box2 .remove', this.container),
-        moveAllButton: $('.box1 .moveall', this.container),
-        removeAllButton: $('.box2 .removeall', this.container),
-        form: $($('.box1 .filter', this.container)[0].form)
-      };
-
-      // Set select IDs
-      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);
-
-      // Apply all settings
-      this.selectedElements = 0;
-      this.sortIndex = 0;
-      this.elementCount = 0;
-      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.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);
-      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);
-
-      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.setSortByInputOrder(this.settings.sortByInputOrder);
-      this.setEventMoveOverride(this.settings.eventMoveOverride);
-      this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);
-      this.setEventRemoveOverride(this.settings.eventRemoveOverride);
-      this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);
-      this.setBtnClass(this.settings.btnClass);
-      this.setBtnMoveText(this.settings.btnMoveText);
-      this.setBtnRemoveText(this.settings.btnRemoveText);
-      this.setBtnMoveAllText(this.settings.btnMoveAllText);
-      this.setBtnRemoveAllText(this.settings.btnRemoveAllText);
-
-      // Hide the original select
-      this.element.hide();
-
-      bindEvents(this);
-      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);
-        });
-        this.elements.moveButton.detach();
-        this.elements.removeButton.detach();
-      } else {
-        this.container.removeClass('moveonselect');
-        this.elements.select1.off('change');
-        this.elements.select2.off('change');
-        this.elements.moveButton.insertAfter(this.elements.moveAllButton);
-        this.elements.removeButton.insertBefore(this.elements.removeAllButton);
-      }
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setMoveOnDoubleClick: function(value, refresh) {
-      if (isBuggyAndroid) {
-        value = false;
-      }
-      this.settings.moveOnDoubleClick = value;
-      if (this.settings.moveOnDoubleClick) {
-        this.container.addClass('moveondoubleclick');
-        var self = this;
-        this.elements.select1.on('dblclick', function() {
-          move(self);
-        });
-        this.elements.select2.on('dblclick', function() {
-          remove(self);
-        });
-      } else {
-        this.container.removeClass('moveondoubleclick');
-        this.elements.select1.off('dblclick');
-        this.elements.select2.off('dblclick');
-      }
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setPreserveSelectionOnMove: function(value, refresh) {
-      // We are forcing to move on select and disabling preserveSelectionOnMove on Android
-      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 (value) {
-        this.elements.info1.show();
-        this.elements.info2.show();
-      } else {
-        this.elements.info1.hide();
-        this.elements.info2.hide();
-      }
-      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;
-    },
-    setSortByInputOrder: function(value, refresh){
-        this.settings.sortByInputOrder = value;
-        if (refresh) {
-          refreshSelects(this);
-        }
-        return this.element;
-    },
-    setEventMoveOverride: function(value, refresh) {
-        this.settings.eventMoveOverride = value;
-        if (refresh) {
-          refreshSelects(this);
-        }
-        return this.element;
-    },
-    setEventMoveAllOverride: function(value, refresh) {
-        this.settings.eventMoveAllOverride = value;
-        if (refresh) {
-          refreshSelects(this);
-        }
-        return this.element;
-    },
-    setEventRemoveOverride: function(value, refresh) {
-        this.settings.eventRemoveOverride = value;
-        if (refresh) {
-          refreshSelects(this);
-        }
-        return this.element;
-    },
-    setEventRemoveAllOverride: function(value, refresh) {
-        this.settings.eventRemoveAllOverride = value;
-        if (refresh) {
-          refreshSelects(this);
-        }
-        return this.element;
-    },
-    setBtnClass: function(value, refresh) {
-      this.settings.btnClass = value;
-      this.elements.moveButton.attr('class', 'btn move').addClass(value);
-      this.elements.removeButton.attr('class', 'btn remove').addClass(value);
-      this.elements.moveAllButton.attr('class', 'btn moveall').addClass(value);
-      this.elements.removeAllButton.attr('class', 'btn removeall').addClass(value);
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setBtnMoveText: function(value, refresh) {
-      this.settings.btnMoveText = value;
-      this.elements.moveButton.html(value);
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setBtnRemoveText: function(value, refresh) {
-      this.settings.btnMoveText = value;
-      this.elements.removeButton.html(value);
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setBtnMoveAllText: function(value, refresh) {
-      this.settings.btnMoveText = value;
-      this.elements.moveAllButton.html(value);
-      if (refresh) {
-        refreshSelects(this);
-      }
-      return this.element;
-    },
-    setBtnRemoveAllText: function(value, refresh) {
-      this.settings.btnMoveText = value;
-      this.elements.removeAllButton.html(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;
-    }
-  };
-
-  // A really lightweight plugin wrapper around the constructor,
-  // preventing against multiple instantiations
-  $.fn[ pluginName ] = function (options) {
-    var args = arguments;
-
-    // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
-    if (options === undefined || typeof options === 'object') {
-      return this.each(function () {
-        // If this is not a select
-        if (!$(this).is('select')) {
-          $(this).find('select').each(function(index, item) {
-            // For each nested select, instantiate the Dual List Box
-            $(item).bootstrapDualListbox(options);
-          });
-        } else if (!$.data(this, 'plugin_' + pluginName)) {
-          // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
-
-          // if it has no instance, create a new one, pass options to our plugin constructor,
-          // and store the plugin instance in the elements jQuery data object.
-          $.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
-        }
-      });
-      // If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
-      // treat this as a call to a public method.
-    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
-
-      // Cache the method call to make it possible to return a value
-      var returns;
-
-      this.each(function () {
-        var instance = $.data(this, 'plugin_' + pluginName);
-        // Tests that there's already a plugin-instance and checks that the requested public method exists
-        if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
-          // Call the method of our plugin instance, and pass it the supplied arguments.
-          returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
-        }
-      });
-
-      // If the earlier cached method gives a value back return the value,
-      // otherwise return this to preserve chainability.
-      return returns !== undefined ? returns : this;
-    }
-
-  };
-
-}));
+(function(factory) {
+  if (typeof define === 'function' && define.amd) {
+    define(['jquery'], factory);
+  } else if (typeof module === 'object' && module.exports) {
+    module.exports = function(root, jQuery) {
+      if (jQuery === undefined) {
+        if (typeof window !== 'undefined') {
+          jQuery = require('jquery');
+        }
+        else {
+          jQuery = require('jquery')(root);
+        }
+      }
+      factory(jQuery);
+      return jQuery;
+    };
+  } else {
+    factory(jQuery);
+  }
+}(function($) {
+  // Create the defaults once
+  var pluginName = 'bootstrapDualListbox',
+    defaults = {
+      filterTextClear: 'show all',
+      filterPlaceHolder: 'Filter',
+      moveSelectedLabel: 'Move selected',
+      moveAllLabel: 'Move all',
+      removeSelectedLabel: 'Remove selected',
+      removeAllLabel: 'Remove all',
+      moveOnSelect: true,                                                                 // true/false (forced true on androids, see the comment later)
+      moveOnDoubleClick: true,                                                            // true/false (forced false on androids, cause moveOnSelect is forced to true)
+      preserveSelectionOnMove: false,                                                     // 'all' / 'moved' / false
+      selectedListLabel: false,                                                           // 'string', false
+      nonSelectedListLabel: false,                                                        // 'string', false
+      helperSelectNamePostfix: '_helper',                                                 // 'string_of_postfix' / false
+      selectorMinimalHeight: 100,
+      showFilterInputs: true,                                                             // whether to show filter inputs
+      nonSelectedFilter: '',                                                              // string, filter the non selected options
+      selectedFilter: '',                                                                 // string, filter the selected options
+      infoText: 'Showing all {0}',                                                        // text when all options are visible / false for no info text
+      infoTextFiltered: '<span class="badge badge-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
+      infoTextEmpty: 'Empty list',                                                        // when there are no options present in the list
+      filterOnValues: false,                                                              // filter by selector's values, boolean
+      sortByInputOrder: false,
+      eventMoveOverride: false,                                                           // boolean, allows user to unbind default event behaviour and run their own instead
+      eventMoveAllOverride: false,                                                        // boolean, allows user to unbind default event behaviour and run their own instead
+      eventRemoveOverride: false,                                                         // boolean, allows user to unbind default event behaviour and run their own instead
+      eventRemoveAllOverride: false,                                                      // boolean, allows user to unbind default event behaviour and run their own instead
+      btnClass: 'btn-outline-secondary',                                                  // sets the button style class for all the buttons
+      btnMoveText: '&gt;',                                                                // string, sets the text for the "Move" button
+      btnRemoveText: '&lt;',                                                              // string, sets the text for the "Remove" button
+      btnMoveAllText: '&gt;&gt;',                                                         // string, sets the text for the "Move All" button
+      btnRemoveAllText: '&lt;&lt;'                                                        // string, sets the text for the "Remove All" button
+    },
+    // Selections are invisible on android if the containing select is styled with CSS
+    // http://code.google.com/p/android/issues/detail?id=16922
+    isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
+
+  // The actual plugin constructor
+  function BootstrapDualListbox(element, options) {
+    this.element = $(element);
+    // jQuery has an extend method which merges the contents of two or
+    // more objects, storing the result in the first object. The first object
+    // is generally empty as we don't want to alter the default options for
+    // future instances of the plugin
+    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);
+        if(selected){
+          $item.attr('data-sortindex', dualListbox.sortIndex);
+          dualListbox.sortIndex++;
+        } else {
+          $item.removeAttr('data-sortindex');
+        }
+      }
+    });
+  }
+
+  function formatString(s, args) {
+    console.log(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 {
+        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,
+      allOptions = dualListbox.element.find('option'),
+      options = dualListbox.element;
+
+    if (selectIndex === 1) {
+      options = allOptions.not(':selected');
+    } else  {
+      options = options.find('option:selected');
+    }
+
+    try {
+      regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi');
+    }
+    catch(e) {
+      // a regex to match nothing
+      regex = new RegExp('/a^/', 'gi');
+    }
+
+    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')));
+      }
+      allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
+    });
+
+    refreshInfo(dualListbox);
+  }
+
+  function saveSelections(dualListbox, selectIndex) {
+    var options = dualListbox.element.find('option');
+    dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
+      var $item = $(item);
+      options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));
+    });
+  }
+
+  function sortOptionsByInputOrder(select){
+    var selectopt = select.children('option');
+
+    selectopt.sort(function(a,b){
+      var an = parseInt(a.getAttribute('data-sortindex')),
+          bn = parseInt(b.getAttribute('data-sortindex'));
+
+          if(an > bn) {
+             return 1;
+          }
+          if(an < bn) {
+            return -1;
+          }
+          return 0;
+    });
+
+    selectopt.detach().appendTo(select);
+  }
+
+  function sortOptions(select, dualListbox) {
+    select.find('option').sort(function(a, b) {
+      return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
+    }).appendTo(select);
+
+    // workaround for chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1072475
+    refreshSelects(dualListbox);
+  }
+
+  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);
+    if(dualListbox.settings.sortByInputOrder){
+        sortOptionsByInputOrder(dualListbox.elements.select2);
+    } else {
+        sortOptions(dualListbox.elements.select2, dualListbox);
+    }
+  }
+
+  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, dualListbox);
+    if(dualListbox.settings.sortByInputOrder){
+        sortOptionsByInputOrder(dualListbox.elements.select2);
+    }
+  }
+
+  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').each(function(index, item) {
+      var $item = $(item);
+      if (!$item.data('filtered1')) {
+        $item.prop('selected', true);
+        $item.attr('data-sortindex', dualListbox.sortIndex);
+        dualListbox.sortIndex++;
+      }
+    });
+
+    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);
+        $item.removeAttr('data-sortindex');
+      }
+    });
+
+    refreshSelects(dualListbox);
+    triggerChangeEvent(dualListbox);
+  }
+
+  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);
+    });
+
+    if (dualListbox.settings.eventMoveOverride === false) {
+      dualListbox.elements.moveButton.on('click', function() {
+        move(dualListbox);
+      });
+    }
+
+    if (dualListbox.settings.eventMoveAllOverride === false) {
+      dualListbox.elements.moveAllButton.on('click', function() {
+        moveAll(dualListbox);
+      });
+    }
+
+    if (dualListbox.settings.eventRemoveOverride === false) {
+      dualListbox.elements.removeButton.on('click', function() {
+        remove(dualListbox);
+      });
+    }
+
+    if (dualListbox.settings.eventRemoveAllOverride === false) {
+      dualListbox.elements.removeAllButton.on('click', function() {
+        removeAll(dualListbox);
+      });
+    }
+
+    dualListbox.elements.filterInput1.on('change keyup', function() {
+      filter(dualListbox, 1);
+    });
+
+    dualListbox.elements.filterInput2.on('change keyup', function() {
+      filter(dualListbox, 2);
+    });
+  }
+
+  BootstrapDualListbox.prototype = {
+    init: function () {
+      // Add the custom HTML template
+      this.container = $('' +
+        '<div class="bootstrap-duallistbox-container row">' +
+        ' <div class="box1 col-md-6">' +
+        '   <label></label>' +
+        '   <span class="info-container">' +
+        '     <span class="info"></span>' +
+        '     <button type="button" class="btn btn-sm clear1" style="float:right!important;"></button>' +
+        '   </span>' +
+        '   <input class="form-control filter" type="text">' +
+        '   <div class="btn-group buttons">' +
+        '     <button type="button" class="btn moveall"></button>' +
+        '     <button type="button" class="btn move"></button>' +
+        '   </div>' +
+        '   <select multiple="multiple"></select>' +
+        ' </div>' +
+        ' <div class="box2 col-md-6">' +
+        '   <label></label>' +
+        '   <span class="info-container">' +
+        '     <span class="info"></span>' +
+        '     <button type="button" class="btn btn-sm clear2" style="float:right!important;"></button>' +
+        '   </span>' +
+        '   <input class="form-control filter" type="text">' +
+        '   <div class="btn-group buttons">' +
+        '     <button type="button" class="btn remove"></button>' +
+        '     <button type="button" class="btn removeall"></button>' +
+        '   </div>' +
+        '   <select multiple="multiple"></select>' +
+        ' </div>' +
+        '</div>')
+        .insertBefore(this.element);
+
+      // Cache the inner elements
+      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: $('.box1 .move', this.container),
+        removeButton: $('.box2 .remove', this.container),
+        moveAllButton: $('.box1 .moveall', this.container),
+        removeAllButton: $('.box2 .removeall', this.container),
+        form: $($('.box1 .filter', this.container)[0].form)
+      };
+
+      // Set select IDs
+      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);
+
+      // Apply all settings
+      this.selectedElements = 0;
+      this.sortIndex = 0;
+      this.elementCount = 0;
+      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.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);
+      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);
+
+      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.setSortByInputOrder(this.settings.sortByInputOrder);
+      this.setEventMoveOverride(this.settings.eventMoveOverride);
+      this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);
+      this.setEventRemoveOverride(this.settings.eventRemoveOverride);
+      this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);
+      this.setBtnClass(this.settings.btnClass);
+      this.setBtnMoveText(this.settings.btnMoveText);
+      this.setBtnRemoveText(this.settings.btnRemoveText);
+      this.setBtnMoveAllText(this.settings.btnMoveAllText);
+      this.setBtnRemoveAllText(this.settings.btnRemoveAllText);
+
+      // Hide the original select
+      this.element.hide();
+
+      bindEvents(this);
+      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);
+        });
+        this.elements.moveButton.detach();
+        this.elements.removeButton.detach();
+      } else {
+        this.container.removeClass('moveonselect');
+        this.elements.select1.off('change');
+        this.elements.select2.off('change');
+        this.elements.moveButton.insertAfter(this.elements.moveAllButton);
+        this.elements.removeButton.insertBefore(this.elements.removeAllButton);
+      }
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setMoveOnDoubleClick: function(value, refresh) {
+      if (isBuggyAndroid) {
+        value = false;
+      }
+      this.settings.moveOnDoubleClick = value;
+      if (this.settings.moveOnDoubleClick) {
+        this.container.addClass('moveondoubleclick');
+        var self = this;
+        this.elements.select1.on('dblclick', function() {
+          move(self);
+        });
+        this.elements.select2.on('dblclick', function() {
+          remove(self);
+        });
+      } else {
+        this.container.removeClass('moveondoubleclick');
+        this.elements.select1.off('dblclick');
+        this.elements.select2.off('dblclick');
+      }
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setPreserveSelectionOnMove: function(value, refresh) {
+      // We are forcing to move on select and disabling preserveSelectionOnMove on Android
+      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 (value) {
+        this.elements.info1.show();
+        this.elements.info2.show();
+      } else {
+        this.elements.info1.hide();
+        this.elements.info2.hide();
+      }
+      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;
+    },
+    setSortByInputOrder: function(value, refresh){
+        this.settings.sortByInputOrder = value;
+        if (refresh) {
+          refreshSelects(this);
+        }
+        return this.element;
+    },
+    setEventMoveOverride: function(value, refresh) {
+        this.settings.eventMoveOverride = value;
+        if (refresh) {
+          refreshSelects(this);
+        }
+        return this.element;
+    },
+    setEventMoveAllOverride: function(value, refresh) {
+        this.settings.eventMoveAllOverride = value;
+        if (refresh) {
+          refreshSelects(this);
+        }
+        return this.element;
+    },
+    setEventRemoveOverride: function(value, refresh) {
+        this.settings.eventRemoveOverride = value;
+        if (refresh) {
+          refreshSelects(this);
+        }
+        return this.element;
+    },
+    setEventRemoveAllOverride: function(value, refresh) {
+        this.settings.eventRemoveAllOverride = value;
+        if (refresh) {
+          refreshSelects(this);
+        }
+        return this.element;
+    },
+    setBtnClass: function(value, refresh) {
+      this.settings.btnClass = value;
+      this.elements.moveButton.attr('class', 'btn move').addClass(value);
+      this.elements.removeButton.attr('class', 'btn remove').addClass(value);
+      this.elements.moveAllButton.attr('class', 'btn moveall').addClass(value);
+      this.elements.removeAllButton.attr('class', 'btn removeall').addClass(value);
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setBtnMoveText: function(value, refresh) {
+      this.settings.btnMoveText = value;
+      this.elements.moveButton.html(value);
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setBtnRemoveText: function(value, refresh) {
+      this.settings.btnMoveText = value;
+      this.elements.removeButton.html(value);
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setBtnMoveAllText: function(value, refresh) {
+      this.settings.btnMoveText = value;
+      this.elements.moveAllButton.html(value);
+      if (refresh) {
+        refreshSelects(this);
+      }
+      return this.element;
+    },
+    setBtnRemoveAllText: function(value, refresh) {
+      this.settings.btnMoveText = value;
+      this.elements.removeAllButton.html(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;
+    }
+  };
+
+  // A really lightweight plugin wrapper around the constructor,
+  // preventing against multiple instantiations
+  $.fn[ pluginName ] = function (options) {
+    var args = arguments;
+
+    // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
+    if (options === undefined || typeof options === 'object') {
+      return this.each(function () {
+        // If this is not a select
+        if (!$(this).is('select')) {
+          $(this).find('select').each(function(index, item) {
+            // For each nested select, instantiate the Dual List Box
+            $(item).bootstrapDualListbox(options);
+          });
+        } else if (!$.data(this, 'plugin_' + pluginName)) {
+          // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
+
+          // if it has no instance, create a new one, pass options to our plugin constructor,
+          // and store the plugin instance in the elements jQuery data object.
+          $.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
+        }
+      });
+      // If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
+      // treat this as a call to a public method.
+    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
+
+      // Cache the method call to make it possible to return a value
+      var returns;
+
+      this.each(function () {
+        var instance = $.data(this, 'plugin_' + pluginName);
+        // Tests that there's already a plugin-instance and checks that the requested public method exists
+        if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
+          // Call the method of our plugin instance, and pass it the supplied arguments.
+          returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
+        }
+      });
+
+      // If the earlier cached method gives a value back return the value,
+      // otherwise return this to preserve chainability.
+      return returns !== undefined ? returns : this;
+    }
+
+  };
+
+}));

File diff suppressed because it is too large
+ 1 - 1
plugins/bootstrap4-duallistbox/jquery.bootstrap-duallistbox.min.js


+ 7 - 7
plugins/datatables-autofill/js/dataTables.autoFill.js

@@ -1,15 +1,15 @@
-/*! AutoFill 2.3.4
- * ©2008-2019 SpryMedia Ltd - datatables.net/license
+/*! AutoFill 2.3.5
+ * ©2008-2020 SpryMedia Ltd - datatables.net/license
  */
 
 /**
  * @summary     AutoFill
  * @description Add Excel like click and drag auto-fill options to DataTables
- * @version     2.3.4
+ * @version     2.3.5
  * @file        dataTables.autoFill.js
  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
  * @contact     www.sprymedia.co.uk/contact
- * @copyright   Copyright 2010-2019 SpryMedia Ltd.
+ * @copyright   Copyright 2010-2020 SpryMedia Ltd.
  *
  * This source file is free software, available under the following license:
  *   MIT license - http://datatables.net/license/mit
@@ -294,7 +294,7 @@ $.extend( AutoFill.prototype, {
 			var result = actions[ available[0] ].execute( dt, cells );
 			this._update( result, cells );
 		}
-		else {
+		else if ( available.length > 1 ) {
 			// Multiple actions available - ask the end user what they want to do
 			var list = this.dom.list.children('ul').empty();
 
@@ -1061,7 +1061,7 @@ AutoFill.actions = {
 
 	fillVertical: {
 		available: function ( dt, cells ) {
-			return cells.length > 1 && cells[0].length > 1;
+			return cells.length > 1;
 		},
 
 		option: function ( dt, cells ) {
@@ -1102,7 +1102,7 @@ AutoFill.actions = {
  * @static
  * @type      String
  */
-AutoFill.version = '2.3.4';
+AutoFill.version = '2.3.5';
 
 
 /**

+ 8 - 2
plugins/datatables-bs4/css/dataTables.bootstrap4.css

@@ -161,8 +161,11 @@ div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
   div.dataTables_wrapper div.dataTables_paginate {
     text-align: center;
   }
+  div.dataTables_wrapper div.dataTables_paginate ul.pagination {
+    justify-content: center !important;
+  }
 }
-table.dataTable.table-sm > thead > tr > th {
+table.dataTable.table-sm > thead > tr > th :not(.sorting_disabled) {
   padding-right: 20px;
 }
 table.dataTable.table-sm .sorting:before,
@@ -177,6 +180,9 @@ table.dataTable.table-sm .sorting_desc:after {
   top: 5px;
 }
 
+table.table-bordered.dataTable {
+  border-right-width: 0;
+}
 table.table-bordered.dataTable th,
 table.table-bordered.dataTable td {
   border-left-width: 0;
@@ -184,7 +190,7 @@ table.table-bordered.dataTable td {
 table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,
 table.table-bordered.dataTable td:last-child,
 table.table-bordered.dataTable td:last-child {
-  border-right-width: 0;
+  border-right-width: 1px;
 }
 table.table-bordered.dataTable tbody th,
 table.table-bordered.dataTable tbody td {

File diff suppressed because it is too large
+ 0 - 0
plugins/datatables-bs4/css/dataTables.bootstrap4.min.css


+ 1 - 1
plugins/datatables-bs4/js/dataTables.bootstrap4.js

@@ -175,7 +175,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
 	);
 
 	if ( activeEl !== undefined ) {
-		$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
+		$(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
 	}
 };
 

+ 1 - 1
plugins/datatables-bs4/js/dataTables.bootstrap4.min.js

@@ -5,4 +5,4 @@
 (function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d,m){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
 renderer:"bootstrap"});b.extend(f.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"custom-select custom-select-sm form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,s,j,n){var o=new f.Api(a),t=a.oClasses,k=a.oLanguage.oPaginate,u=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault();
 !b(a.currentTarget).hasClass("disabled")&&o.page()!=a.data.action&&o.page(a.data.action).draw("page")};l=0;for(h=f.length;l<h;l++)if(c=f[l],b.isArray(c))q(d,c);else{g=e="";switch(c){case "ellipsis":e="&#x2026;";g="disabled";break;case "first":e=k.sFirst;g=c+(0<j?"":" disabled");break;case "previous":e=k.sPrevious;g=c+(0<j?"":" disabled");break;case "next":e=k.sNext;g=c+(j<n-1?"":" disabled");break;case "last":e=k.sLast;g=c+(j<n-1?"":" disabled");break;default:e=c+1,g=j===c?"active":""}e&&(i=b("<li>",
-{"class":t.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("<a>",{href:"#","aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex,"class":"page-link"}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('<ul class="pagination"/>').children("ul"),s);i!==m&&b(h).find("[data-dt-idx="+i+"]").focus()};return f});
+{"class":t.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("<a>",{href:"#","aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex,"class":"page-link"}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('<ul class="pagination"/>').children("ul"),s);i!==m&&b(h).find("[data-dt-idx="+i+"]").trigger("focus")};return f});

Some files were not shown because too many files changed in this diff