Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
28071 tejbeer 1
/*
2
 *  Bootstrap Duallistbox - v3.0.9
3
 *  A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
4
 *  https://www.virtuosoft.eu/code/bootstrap-duallistbox/
5
 *
6
 *  Made by István Ujj-Mészáros
7
 *  Under Apache License v2.0 License
8
 */
9
;(function ($, window, document, undefined) {
10
  // Create the defaults once
11
  var pluginName = 'bootstrapDualListbox',
12
    defaults = {
13
      bootstrap2Compatible: false,
14
      filterTextClear: 'show all',
15
      filterPlaceHolder: 'Filter',
16
      moveSelectedLabel: 'Move selected',
17
      moveAllLabel: 'Move all',
18
      removeSelectedLabel: 'Remove selected',
19
      removeAllLabel: 'Remove all',
20
      moveOnSelect: true,                                                                 // true/false (forced true on androids, see the comment later)
21
      moveOnDoubleClick: true,                                                            // true/false (forced false on androids, cause moveOnSelect is forced to true)
22
      preserveSelectionOnMove: false,                                                     // 'all' / 'moved' / false
23
      selectedListLabel: false,                                                           // 'string', false
24
      nonSelectedListLabel: false,                                                        // 'string', false
25
      helperSelectNamePostfix: '_helper',                                                 // 'string_of_postfix' / false
26
      selectorMinimalHeight: 100,
27
      showFilterInputs: true,                                                             // whether to show filter inputs
28
      nonSelectedFilter: '',                                                              // string, filter the non selected options
29
      selectedFilter: '',                                                                 // string, filter the selected options
30
      infoText: 'Showing all {0}',                                                        // text when all options are visible / false for no info text
31
      infoTextFiltered: '<span class="label label-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
32
      infoTextEmpty: 'Empty list',                                                        // when there are no options present in the list
33
      filterOnValues: false,                                                              // filter by selector's values, boolean
34
      sortByInputOrder: false,
35
      eventMoveOverride: false,                                                           // boolean, allows user to unbind default event behaviour and run their own instead
36
      eventMoveAllOverride: false,                                                        // boolean, allows user to unbind default event behaviour and run their own instead
37
      eventRemoveOverride: false,                                                         // boolean, allows user to unbind default event behaviour and run their own instead
38
      eventRemoveAllOverride: false                                                       // boolean, allows user to unbind default event behaviour and run their own instead
39
    },
40
    // Selections are invisible on android if the containing select is styled with CSS
41
    // http://code.google.com/p/android/issues/detail?id=16922
42
    isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
43
 
44
  // The actual plugin constructor
45
  function BootstrapDualListbox(element, options) {
46
    this.element = $(element);
47
    // jQuery has an extend method which merges the contents of two or
48
    // more objects, storing the result in the first object. The first object
49
    // is generally empty as we don't want to alter the default options for
50
    // future instances of the plugin
51
    this.settings = $.extend({}, defaults, options);
52
    this._defaults = defaults;
53
    this._name = pluginName;
54
    this.init();
55
  }
56
 
57
  function triggerChangeEvent(dualListbox) {
58
    dualListbox.element.trigger('change');
59
  }
60
 
61
  function updateSelectionStates(dualListbox) {
62
    dualListbox.element.find('option').each(function(index, item) {
63
      var $item = $(item);
64
      if (typeof($item.data('original-index')) === 'undefined') {
65
        $item.data('original-index', dualListbox.elementCount++);
66
      }
67
      if (typeof($item.data('_selected')) === 'undefined') {
68
        $item.data('_selected', false);
69
      }
70
    });
71
  }
72
 
73
  function changeSelectionState(dualListbox, original_index, selected) {
74
    dualListbox.element.find('option').each(function(index, item) {
75
      var $item = $(item);
76
      if ($item.data('original-index') === original_index) {
77
        $item.prop('selected', selected);
78
        if(selected){
79
          $item.attr('data-sortindex', dualListbox.sortIndex);
80
          dualListbox.sortIndex++;
81
        } else {
82
          $item.removeAttr('data-sortindex');
83
        }
84
      }
85
    });
86
  }
87
 
88
  function formatString(s, args) {
89
    return s.replace(/\{(\d+)\}/g, function(match, number) {
90
      return typeof args[number] !== 'undefined' ? args[number] : match;
91
    });
92
  }
93
 
94
  function refreshInfo(dualListbox) {
95
    if (!dualListbox.settings.infoText) {
96
      return;
97
    }
98
 
99
    var visible1 = dualListbox.elements.select1.find('option').length,
100
      visible2 = dualListbox.elements.select2.find('option').length,
101
      all1 = dualListbox.element.find('option').length - dualListbox.selectedElements,
102
      all2 = dualListbox.selectedElements,
103
      content = '';
104
 
105
    if (all1 === 0) {
106
      content = dualListbox.settings.infoTextEmpty;
107
    } else if (visible1 === all1) {
108
      content = formatString(dualListbox.settings.infoText, [visible1, all1]);
109
    } else {
110
      content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]);
111
    }
112
 
113
    dualListbox.elements.info1.html(content);
114
    dualListbox.elements.box1.toggleClass('filtered', !(visible1 === all1 || all1 === 0));
115
 
116
    if (all2 === 0) {
117
      content = dualListbox.settings.infoTextEmpty;
118
    } else if (visible2 === all2) {
119
      content = formatString(dualListbox.settings.infoText, [visible2, all2]);
120
    } else {
121
      content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]);
122
    }
123
 
124
    dualListbox.elements.info2.html(content);
125
    dualListbox.elements.box2.toggleClass('filtered', !(visible2 === all2 || all2 === 0));
126
  }
127
 
128
  function refreshSelects(dualListbox) {
129
    dualListbox.selectedElements = 0;
130
 
131
    dualListbox.elements.select1.empty();
132
    dualListbox.elements.select2.empty();
133
 
134
    dualListbox.element.find('option').each(function(index, item) {
135
      var $item = $(item);
136
      if ($item.prop('selected')) {
137
        dualListbox.selectedElements++;
138
        dualListbox.elements.select2.append($item.clone(true).prop('selected', $item.data('_selected')));
139
      } else {
140
        dualListbox.elements.select1.append($item.clone(true).prop('selected', $item.data('_selected')));
141
      }
142
    });
143
 
144
    if (dualListbox.settings.showFilterInputs) {
145
      filter(dualListbox, 1);
146
      filter(dualListbox, 2);
147
    }
148
    refreshInfo(dualListbox);
149
  }
150
 
151
  function filter(dualListbox, selectIndex) {
152
    if (!dualListbox.settings.showFilterInputs) {
153
      return;
154
    }
155
 
156
    saveSelections(dualListbox, selectIndex);
157
 
158
    dualListbox.elements['select'+selectIndex].empty().scrollTop(0);
159
    var regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi'),
160
      allOptions = dualListbox.element.find('option'),
161
      options = dualListbox.element;
162
 
163
    if (selectIndex === 1) {
164
      options = allOptions.not(':selected');
165
    } else  {
166
      options = options.find('option:selected');
167
    }
168
 
169
    options.each(function(index, item) {
170
      var $item = $(item),
171
        isFiltered = true;
172
      if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) ) ) {
173
        isFiltered = false;
174
        dualListbox.elements['select'+selectIndex].append($item.clone(true).prop('selected', $item.data('_selected')));
175
      }
176
      allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
177
    });
178
 
179
    refreshInfo(dualListbox);
180
  }
181
 
182
  function saveSelections(dualListbox, selectIndex) {
183
    var options = dualListbox.element.find('option');
184
    dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
185
      var $item = $(item);
186
      options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));
187
    });
188
  }
189
 
190
  function sortOptionsByInputOrder(select){
191
    var selectopt = select.children('option');
192
 
193
    selectopt.sort(function(a,b){
194
      var an = parseInt(a.getAttribute('data-sortindex')),
195
          bn = parseInt(b.getAttribute('data-sortindex'));
196
 
197
          if(an > bn) {
198
             return 1;
199
          }
200
          if(an < bn) {
201
            return -1;
202
          }
203
          return 0;
204
    });
205
 
206
    selectopt.detach().appendTo(select);
207
  }
208
 
209
  function sortOptions(select, dualListbox) {
210
    select.find('option').sort(function(a, b) {
211
      return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
212
    }).appendTo(select);
213
 
214
    // workaround for chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1072475
215
    refreshSelects(dualListbox);
216
  }
217
 
218
  function clearSelections(dualListbox) {
219
    dualListbox.elements.select1.find('option').each(function() {
220
      dualListbox.element.find('option').data('_selected', false);
221
    });
222
  }
223
 
224
  function move(dualListbox) {
225
    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
226
      saveSelections(dualListbox, 1);
227
      saveSelections(dualListbox, 2);
228
    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
229
      saveSelections(dualListbox, 1);
230
    }
231
 
232
    dualListbox.elements.select1.find('option:selected').each(function(index, item) {
233
      var $item = $(item);
234
      if (!$item.data('filtered1')) {
235
        changeSelectionState(dualListbox, $item.data('original-index'), true);
236
      }
237
    });
238
 
239
    refreshSelects(dualListbox);
240
    triggerChangeEvent(dualListbox);
241
    if(dualListbox.settings.sortByInputOrder){
242
        sortOptionsByInputOrder(dualListbox.elements.select2);
243
    } else {
244
        sortOptions(dualListbox.elements.select2, dualListbox);
245
    }
246
  }
247
 
248
  function remove(dualListbox) {
249
    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
250
      saveSelections(dualListbox, 1);
251
      saveSelections(dualListbox, 2);
252
    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
253
      saveSelections(dualListbox, 2);
254
    }
255
 
256
    dualListbox.elements.select2.find('option:selected').each(function(index, item) {
257
      var $item = $(item);
258
      if (!$item.data('filtered2')) {
259
        changeSelectionState(dualListbox, $item.data('original-index'), false);
260
      }
261
    });
262
 
263
    refreshSelects(dualListbox);
264
    triggerChangeEvent(dualListbox);
265
    sortOptions(dualListbox.elements.select1, dualListbox);
266
    if(dualListbox.settings.sortByInputOrder){
267
        sortOptionsByInputOrder(dualListbox.elements.select2);
268
    }
269
  }
270
 
271
  function moveAll(dualListbox) {
272
    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
273
      saveSelections(dualListbox, 1);
274
      saveSelections(dualListbox, 2);
275
    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
276
      saveSelections(dualListbox, 1);
277
    }
278
 
279
    dualListbox.element.find('option').each(function(index, item) {
280
      var $item = $(item);
281
      if (!$item.data('filtered1')) {
282
        $item.prop('selected', true);
283
        $item.attr('data-sortindex', dualListbox.sortIndex);
284
        dualListbox.sortIndex++;
285
      }
286
    });
287
 
288
    refreshSelects(dualListbox);
289
    triggerChangeEvent(dualListbox);
290
  }
291
 
292
  function removeAll(dualListbox) {
293
    if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
294
      saveSelections(dualListbox, 1);
295
      saveSelections(dualListbox, 2);
296
    } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
297
      saveSelections(dualListbox, 2);
298
    }
299
 
300
    dualListbox.element.find('option').each(function(index, item) {
301
      var $item = $(item);
302
      if (!$item.data('filtered2')) {
303
        $item.prop('selected', false);
304
        $item.removeAttr('data-sortindex');
305
      }
306
    });
307
 
308
    refreshSelects(dualListbox);
309
    triggerChangeEvent(dualListbox);
310
  }
311
 
312
  function bindEvents(dualListbox) {
313
    dualListbox.elements.form.submit(function(e) {
314
      if (dualListbox.elements.filterInput1.is(':focus')) {
315
        e.preventDefault();
316
        dualListbox.elements.filterInput1.focusout();
317
      } else if (dualListbox.elements.filterInput2.is(':focus')) {
318
        e.preventDefault();
319
        dualListbox.elements.filterInput2.focusout();
320
      }
321
    });
322
 
323
    dualListbox.element.on('bootstrapDualListbox.refresh', function(e, mustClearSelections){
324
      dualListbox.refresh(mustClearSelections);
325
    });
326
 
327
    dualListbox.elements.filterClear1.on('click', function() {
328
      dualListbox.setNonSelectedFilter('', true);
329
    });
330
 
331
    dualListbox.elements.filterClear2.on('click', function() {
332
      dualListbox.setSelectedFilter('', true);
333
    });
334
 
335
    if (dualListbox.settings.eventMoveOverride === false) {
336
      dualListbox.elements.moveButton.on('click', function() {
337
        move(dualListbox);
338
      });
339
    }
340
 
341
    if (dualListbox.settings.eventMoveAllOverride === false) {
342
      dualListbox.elements.moveAllButton.on('click', function() {
343
        moveAll(dualListbox);
344
      });
345
    }
346
 
347
    if (dualListbox.settings.eventRemoveOverride === false) {
348
      dualListbox.elements.removeButton.on('click', function() {
349
        remove(dualListbox);
350
      });
351
    }
352
 
353
    if (dualListbox.settings.eventRemoveAllOverride === false) {
354
      dualListbox.elements.removeAllButton.on('click', function() {
355
        removeAll(dualListbox);
356
      });
357
    }
358
 
359
    dualListbox.elements.filterInput1.on('change keyup', function() {
360
      filter(dualListbox, 1);
361
    });
362
 
363
    dualListbox.elements.filterInput2.on('change keyup', function() {
364
      filter(dualListbox, 2);
365
    });
366
  }
367
 
368
  BootstrapDualListbox.prototype = {
369
    init: function () {
370
      // Add the custom HTML template
371
      this.container = $('' +
372
        '<div class="bootstrap-duallistbox-container">' +
373
        ' <div class="box1">' +
374
        '   <label></label>' +
375
        '   <span class="info-container">' +
376
        '     <span class="info"></span>' +
377
        '     <button type="button" class="btn clear1 pull-right"></button>' +
378
        '   </span>' +
379
        '   <input class="filter" type="text">' +
380
        '   <div class="btn-group buttons">' +
381
        '     <button type="button" class="btn moveall">' +
382
        '       <i></i>' +
383
        '       <i></i>' +
384
        '     </button>' +
385
        '     <button type="button" class="btn move">' +
386
        '       <i></i>' +
387
        '     </button>' +
388
        '   </div>' +
389
        '   <select multiple="multiple"></select>' +
390
        ' </div>' +
391
        ' <div class="box2">' +
392
        '   <label></label>' +
393
        '   <span class="info-container">' +
394
        '     <span class="info"></span>' +
395
        '     <button type="button" class="btn clear2 pull-right"></button>' +
396
        '   </span>' +
397
        '   <input class="filter" type="text">' +
398
        '   <div class="btn-group buttons">' +
399
        '     <button type="button" class="btn remove">' +
400
        '       <i></i>' +
401
        '     </button>' +
402
        '     <button type="button" class="btn removeall">' +
403
        '       <i></i>' +
404
        '       <i></i>' +
405
        '     </button>' +
406
        '   </div>' +
407
        '   <select multiple="multiple"></select>' +
408
        ' </div>' +
409
        '</div>')
410
        .insertBefore(this.element);
411
 
412
      // Cache the inner elements
413
      this.elements = {
414
        originalSelect: this.element,
415
        box1: $('.box1', this.container),
416
        box2: $('.box2', this.container),
417
        filterInput1: $('.box1 .filter', this.container),
418
        filterInput2: $('.box2 .filter', this.container),
419
        filterClear1: $('.box1 .clear1', this.container),
420
        filterClear2: $('.box2 .clear2', this.container),
421
        label1: $('.box1 > label', this.container),
422
        label2: $('.box2 > label', this.container),
423
        info1: $('.box1 .info', this.container),
424
        info2: $('.box2 .info', this.container),
425
        select1: $('.box1 select', this.container),
426
        select2: $('.box2 select', this.container),
427
        moveButton: $('.box1 .move', this.container),
428
        removeButton: $('.box2 .remove', this.container),
429
        moveAllButton: $('.box1 .moveall', this.container),
430
        removeAllButton: $('.box2 .removeall', this.container),
431
        form: $($('.box1 .filter', this.container)[0].form)
432
      };
433
 
434
      // Set select IDs
435
      this.originalSelectName = this.element.attr('name') || '';
436
      var select1Id = 'bootstrap-duallistbox-nonselected-list_' + this.originalSelectName,
437
        select2Id = 'bootstrap-duallistbox-selected-list_' + this.originalSelectName;
438
      this.elements.select1.attr('id', select1Id);
439
      this.elements.select2.attr('id', select2Id);
440
      this.elements.label1.attr('for', select1Id);
441
      this.elements.label2.attr('for', select2Id);
442
 
443
      // Apply all settings
444
      this.selectedElements = 0;
445
      this.sortIndex = 0;
446
      this.elementCount = 0;
447
      this.setBootstrap2Compatible(this.settings.bootstrap2Compatible);
448
      this.setFilterTextClear(this.settings.filterTextClear);
449
      this.setFilterPlaceHolder(this.settings.filterPlaceHolder);
450
      this.setMoveSelectedLabel(this.settings.moveSelectedLabel);
451
      this.setMoveAllLabel(this.settings.moveAllLabel);
452
      this.setRemoveSelectedLabel(this.settings.removeSelectedLabel);
453
      this.setRemoveAllLabel(this.settings.removeAllLabel);
454
      this.setMoveOnSelect(this.settings.moveOnSelect);
455
      this.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);
456
      this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove);
457
      this.setSelectedListLabel(this.settings.selectedListLabel);
458
      this.setNonSelectedListLabel(this.settings.nonSelectedListLabel);
459
      this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix);
460
      this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight);
461
 
462
      updateSelectionStates(this);
463
 
464
      this.setShowFilterInputs(this.settings.showFilterInputs);
465
      this.setNonSelectedFilter(this.settings.nonSelectedFilter);
466
      this.setSelectedFilter(this.settings.selectedFilter);
467
      this.setInfoText(this.settings.infoText);
468
      this.setInfoTextFiltered(this.settings.infoTextFiltered);
469
      this.setInfoTextEmpty(this.settings.infoTextEmpty);
470
      this.setFilterOnValues(this.settings.filterOnValues);
471
      this.setSortByInputOrder(this.settings.sortByInputOrder);
472
      this.setEventMoveOverride(this.settings.eventMoveOverride);
473
      this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);
474
      this.setEventRemoveOverride(this.settings.eventRemoveOverride);
475
      this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);
476
 
477
      // Hide the original select
478
      this.element.hide();
479
 
480
      bindEvents(this);
481
      refreshSelects(this);
482
 
483
      return this.element;
484
    },
485
    setBootstrap2Compatible: function(value, refresh) {
486
      this.settings.bootstrap2Compatible = value;
487
      if (value) {
488
        this.container.removeClass('row').addClass('row-fluid bs2compatible');
489
        this.container.find('.box1, .box2').removeClass('col-md-6').addClass('span6');
490
        this.container.find('.clear1, .clear2').removeClass('btn-default btn-xs').addClass('btn-mini');
491
        this.container.find('input, select').removeClass('form-control');
492
        this.container.find('.btn').removeClass('btn-default');
493
        this.container.find('.moveall > i, .move > i').removeClass('glyphicon glyphicon-arrow-right').addClass('icon-arrow-right');
494
        this.container.find('.removeall > i, .remove > i').removeClass('glyphicon glyphicon-arrow-left').addClass('icon-arrow-left');
495
      } else {
496
        this.container.removeClass('row-fluid bs2compatible').addClass('row');
497
        this.container.find('.box1, .box2').removeClass('span6').addClass('col-md-6');
498
        this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-default btn-xs');
499
        this.container.find('input, select').addClass('form-control');
500
        this.container.find('.btn').addClass('btn-default');
501
        this.container.find('.moveall > i, .move > i').removeClass('icon-arrow-right').addClass('glyphicon glyphicon-arrow-right');
502
        this.container.find('.removeall > i, .remove > i').removeClass('icon-arrow-left').addClass('glyphicon glyphicon-arrow-left');
503
      }
504
      if (refresh) {
505
        refreshSelects(this);
506
      }
507
      return this.element;
508
    },
509
    setFilterTextClear: function(value, refresh) {
510
      this.settings.filterTextClear = value;
511
      this.elements.filterClear1.html(value);
512
      this.elements.filterClear2.html(value);
513
      if (refresh) {
514
        refreshSelects(this);
515
      }
516
      return this.element;
517
    },
518
    setFilterPlaceHolder: function(value, refresh) {
519
      this.settings.filterPlaceHolder = value;
520
      this.elements.filterInput1.attr('placeholder', value);
521
      this.elements.filterInput2.attr('placeholder', value);
522
      if (refresh) {
523
        refreshSelects(this);
524
      }
525
      return this.element;
526
    },
527
    setMoveSelectedLabel: function(value, refresh) {
528
      this.settings.moveSelectedLabel = value;
529
      this.elements.moveButton.attr('title', value);
530
      if (refresh) {
531
        refreshSelects(this);
532
      }
533
      return this.element;
534
    },
535
    setMoveAllLabel: function(value, refresh) {
536
      this.settings.moveAllLabel = value;
537
      this.elements.moveAllButton.attr('title', value);
538
      if (refresh) {
539
        refreshSelects(this);
540
      }
541
      return this.element;
542
    },
543
    setRemoveSelectedLabel: function(value, refresh) {
544
      this.settings.removeSelectedLabel = value;
545
      this.elements.removeButton.attr('title', value);
546
      if (refresh) {
547
        refreshSelects(this);
548
      }
549
      return this.element;
550
    },
551
    setRemoveAllLabel: function(value, refresh) {
552
      this.settings.removeAllLabel = value;
553
      this.elements.removeAllButton.attr('title', value);
554
      if (refresh) {
555
        refreshSelects(this);
556
      }
557
      return this.element;
558
    },
559
    setMoveOnSelect: function(value, refresh) {
560
      if (isBuggyAndroid) {
561
        value = true;
562
      }
563
      this.settings.moveOnSelect = value;
564
      if (this.settings.moveOnSelect) {
565
        this.container.addClass('moveonselect');
566
        var self = this;
567
        this.elements.select1.on('change', function() {
568
          move(self);
569
        });
570
        this.elements.select2.on('change', function() {
571
          remove(self);
572
        });
573
      } else {
574
        this.container.removeClass('moveonselect');
575
        this.elements.select1.off('change');
576
        this.elements.select2.off('change');
577
      }
578
      if (refresh) {
579
        refreshSelects(this);
580
      }
581
      return this.element;
582
    },
583
    setMoveOnDoubleClick: function(value, refresh) {
584
      if (isBuggyAndroid) {
585
        value = false;
586
      }
587
      this.settings.moveOnDoubleClick = value;
588
      if (this.settings.moveOnDoubleClick) {
589
        this.container.addClass('moveondoubleclick');
590
        var self = this;
591
        this.elements.select1.on('dblclick', function() {
592
          move(self);
593
        });
594
        this.elements.select2.on('dblclick', function() {
595
          remove(self);
596
        });
597
      } else {
598
        this.container.removeClass('moveondoubleclick');
599
        this.elements.select1.off('dblclick');
600
        this.elements.select2.off('dblclick');
601
      }
602
      if (refresh) {
603
        refreshSelects(this);
604
      }
605
      return this.element;
606
    },
607
    setPreserveSelectionOnMove: function(value, refresh) {
608
      // We are forcing to move on select and disabling preserveSelectionOnMove on Android
609
      if (isBuggyAndroid) {
610
        value = false;
611
      }
612
      this.settings.preserveSelectionOnMove = value;
613
      if (refresh) {
614
        refreshSelects(this);
615
      }
616
      return this.element;
617
    },
618
    setSelectedListLabel: function(value, refresh) {
619
      this.settings.selectedListLabel = value;
620
      if (value) {
621
        this.elements.label2.show().html(value);
622
      } else {
623
        this.elements.label2.hide().html(value);
624
      }
625
      if (refresh) {
626
        refreshSelects(this);
627
      }
628
      return this.element;
629
    },
630
    setNonSelectedListLabel: function(value, refresh) {
631
      this.settings.nonSelectedListLabel = value;
632
      if (value) {
633
        this.elements.label1.show().html(value);
634
      } else {
635
        this.elements.label1.hide().html(value);
636
      }
637
      if (refresh) {
638
        refreshSelects(this);
639
      }
640
      return this.element;
641
    },
642
    setHelperSelectNamePostfix: function(value, refresh) {
643
      this.settings.helperSelectNamePostfix = value;
644
      if (value) {
645
        this.elements.select1.attr('name', this.originalSelectName + value + '1');
646
        this.elements.select2.attr('name', this.originalSelectName + value + '2');
647
      } else {
648
        this.elements.select1.removeAttr('name');
649
        this.elements.select2.removeAttr('name');
650
      }
651
      if (refresh) {
652
        refreshSelects(this);
653
      }
654
      return this.element;
655
    },
656
    setSelectOrMinimalHeight: function(value, refresh) {
657
      this.settings.selectorMinimalHeight = value;
658
      var height = this.element.height();
659
      if (this.element.height() < value) {
660
        height = value;
661
      }
662
      this.elements.select1.height(height);
663
      this.elements.select2.height(height);
664
      if (refresh) {
665
        refreshSelects(this);
666
      }
667
      return this.element;
668
    },
669
    setShowFilterInputs: function(value, refresh) {
670
      if (!value) {
671
        this.setNonSelectedFilter('');
672
        this.setSelectedFilter('');
673
        refreshSelects(this);
674
        this.elements.filterInput1.hide();
675
        this.elements.filterInput2.hide();
676
      } else {
677
        this.elements.filterInput1.show();
678
        this.elements.filterInput2.show();
679
      }
680
      this.settings.showFilterInputs = value;
681
      if (refresh) {
682
        refreshSelects(this);
683
      }
684
      return this.element;
685
    },
686
    setNonSelectedFilter: function(value, refresh) {
687
      if (this.settings.showFilterInputs) {
688
        this.settings.nonSelectedFilter = value;
689
        this.elements.filterInput1.val(value);
690
        if (refresh) {
691
          refreshSelects(this);
692
        }
693
        return this.element;
694
      }
695
    },
696
    setSelectedFilter: function(value, refresh) {
697
      if (this.settings.showFilterInputs) {
698
        this.settings.selectedFilter = value;
699
        this.elements.filterInput2.val(value);
700
        if (refresh) {
701
          refreshSelects(this);
702
        }
703
        return this.element;
704
      }
705
    },
706
    setInfoText: function(value, refresh) {
707
      this.settings.infoText = value;
708
      if (value) {
709
        this.elements.info1.show();
710
        this.elements.info2.show();
711
      } else {
712
        this.elements.info1.hide();
713
        this.elements.info2.hide();
714
      }
715
      if (refresh) {
716
        refreshSelects(this);
717
      }
718
      return this.element;
719
    },
720
    setInfoTextFiltered: function(value, refresh) {
721
      this.settings.infoTextFiltered = value;
722
      if (refresh) {
723
        refreshSelects(this);
724
      }
725
      return this.element;
726
    },
727
    setInfoTextEmpty: function(value, refresh) {
728
      this.settings.infoTextEmpty = value;
729
      if (refresh) {
730
        refreshSelects(this);
731
      }
732
      return this.element;
733
    },
734
    setFilterOnValues: function(value, refresh) {
735
      this.settings.filterOnValues = value;
736
      if (refresh) {
737
        refreshSelects(this);
738
      }
739
      return this.element;
740
    },
741
    setSortByInputOrder: function(value, refresh){
742
        this.settings.sortByInputOrder = value;
743
        if (refresh) {
744
          refreshSelects(this);
745
        }
746
        return this.element;
747
    },
748
    setEventMoveOverride: function(value, refresh) {
749
        this.settings.eventMoveOverride = value;
750
        if (refresh) {
751
          refreshSelects(this);
752
        }
753
        return this.element;
754
    },
755
    setEventMoveAllOverride: function(value, refresh) {
756
        this.settings.eventMoveAllOverride = value;
757
        if (refresh) {
758
          refreshSelects(this);
759
        }
760
        return this.element;
761
    },
762
    setEventRemoveOverride: function(value, refresh) {
763
        this.settings.eventRemoveOverride = value;
764
        if (refresh) {
765
          refreshSelects(this);
766
        }
767
        return this.element;
768
    },
769
    setEventRemoveAllOverride: function(value, refresh) {
770
        this.settings.eventRemoveAllOverride = value;
771
        if (refresh) {
772
          refreshSelects(this);
773
        }
774
        return this.element;
775
    },
776
    getContainer: function() {
777
      return this.container;
778
    },
779
    refresh: function(mustClearSelections) {
780
      updateSelectionStates(this);
781
 
782
      if (!mustClearSelections) {
783
        saveSelections(this, 1);
784
        saveSelections(this, 2);
785
      } else {
786
        clearSelections(this);
787
      }
788
 
789
      refreshSelects(this);
790
    },
791
    destroy: function() {
792
      this.container.remove();
793
      this.element.show();
794
      $.data(this, 'plugin_' + pluginName, null);
795
      return this.element;
796
    }
797
  };
798
 
799
  // A really lightweight plugin wrapper around the constructor,
800
  // preventing against multiple instantiations
801
  $.fn[ pluginName ] = function (options) {
802
    var args = arguments;
803
 
804
    // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
805
    if (options === undefined || typeof options === 'object') {
806
      return this.each(function () {
807
        // If this is not a select
808
        if (!$(this).is('select')) {
809
          $(this).find('select').each(function(index, item) {
810
            // For each nested select, instantiate the Dual List Box
811
            $(item).bootstrapDualListbox(options);
812
          });
813
        } else if (!$.data(this, 'plugin_' + pluginName)) {
814
          // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
815
 
816
          // if it has no instance, create a new one, pass options to our plugin constructor,
817
          // and store the plugin instance in the elements jQuery data object.
818
          $.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
819
        }
820
      });
821
      // If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
822
      // treat this as a call to a public method.
823
    } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
824
 
825
      // Cache the method call to make it possible to return a value
826
      var returns;
827
 
828
      this.each(function () {
829
        var instance = $.data(this, 'plugin_' + pluginName);
830
        // Tests that there's already a plugin-instance and checks that the requested public method exists
831
        if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
832
          // Call the method of our plugin instance, and pass it the supplied arguments.
833
          returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
834
        }
835
      });
836
 
837
      // If the earlier cached method gives a value back return the value,
838
      // otherwise return this to preserve chainability.
839
      return returns !== undefined ? returns : this;
840
    }
841
 
842
  };
843
 
844
})(jQuery, window, document);