jquery.bootstrap-duallistbox.js 31 KB

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