jquery.multiselect.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. define([
  2. "jquery"
  3. ], function($){
  4. /*
  5. * jQuery.multiselect plugin
  6. *
  7. * Form control: allow select several values from list and add new value(s) to list
  8. *
  9. * Licensed under the BSD License:
  10. * http://www.opensource.org/licenses/bsd-license
  11. *
  12. * Version: 0.9.0
  13. *
  14. * @author Dmitry (dio) Levashov, dio@std42.ru
  15. * @example
  16. * html: <select name="my-select" multiple="on"><option .... </select>
  17. * js : $('select[name="my-select"]').multiselect()
  18. * or
  19. * var opts = { ... };
  20. * $('select[name="my-select"]').multiselect(opts);
  21. */
  22. $.fn.multiselect = function(opts) {
  23. var o = $.extend({
  24. mselectHiddenClass: 'mselect-hidden',
  25. mselectItemNotEditableClass: 'mselect-list-item-not-editable',
  26. mselectItemNotRemovableClass: 'mselect-list-item-not-removable',
  27. mselectListClass: 'mselect-list',
  28. mselectItemsWrapperClass: 'mselect-items-wrapper',
  29. mselectButtonAddClass: 'mselect-button-add',
  30. mselectInputContainerClass: 'mselect-input-container',
  31. mselectInputClass: 'mselect-input',
  32. mselectButtonCancelClass: 'mselect-cancel',
  33. mselectButtonSaveClass: 'mselect-save',
  34. mselectListItemClass: 'mselect-list-item',
  35. mselectItemsWrapperOverflowClass: 'mselect-fixed',
  36. mselectDisabledClass: 'mselect-disabled',
  37. mselectCheckedClass: 'mselect-checked',
  38. layout: '<section class="block %mselectListClass%">'
  39. +'<div class="block-content"><div class="%mselectItemsWrapperClass%">'
  40. +'%items%'
  41. +'</div></div>'
  42. +'<footer class="block-footer">'
  43. +'<span class="action-add %mselectButtonAddClass%">%addText%</span>'
  44. +'</footer>'
  45. +'<div class="%mselectInputContainerClass%">'
  46. +'<input type="text" class="%mselectInputClass%" title="%inputTitle%"/>'
  47. +'<span class="%mselectButtonCancelClass%" title="%cancelText%"></span>'
  48. +'<span class="%mselectButtonSaveClass%" title="Add"></span>'
  49. +'</div>'
  50. +'</section>',
  51. item : '<div class="%mselectListItemClass% %mselectDisabledClass% %iseditable% %isremovable%"><label><input type="checkbox" class="%mselectCheckedClass%" value="%value%" %checked% %disabled% /><span>%label%</span></label>' +
  52. '<span class="mselect-edit" title="Edit">Edit</span>' +
  53. '<span class="mselect-delete" title="Delete">Delete</span> ' +
  54. '</div>',
  55. addText: 'Add new value',
  56. cancelText: 'Cancel',
  57. inputTitle: 'Enter new option',
  58. size: 5,
  59. keyCodes: {
  60. Enter: 13,
  61. Esc: 27
  62. },
  63. toggleAddButton: true,
  64. // New option for callback
  65. mselectInputSubmitCallback: null,
  66. parse : function(v) { return v.split(/\s*,\s*/); }
  67. }, opts||{});
  68. return this.filter('select[multiple]:not(.' + o.mselectHiddenClass + ')').each(function() {
  69. var select = $(this).addClass(o.mselectHiddenClass).hide(),
  70. size = select.attr('size') > 0 ? select.attr('size') : o.size,
  71. items = (function() {
  72. var str = '';
  73. select.children('option').each(function(i, option) {
  74. option = $(option);
  75. str += o.item
  76. .replace(/%value%/gi, option.val())
  77. .replace(/%checked%/gi, option.attr('selected') ? 'checked' : '')
  78. .replace(/%mselectCheckedClass%/gi, option.attr('selected') ? ''+o.mselectCheckedClass+'' : '')
  79. .replace(/%disabled%/gi, option.attr('disabled') ? 'disabled' : '')
  80. .replace(/%mselectDisabledClass%/gi, option.attr('disabled') ? ''+o.mselectDisabledClass+'' : '')
  81. .replace(/%mselectListItemClass%/gi, o.mselectListItemClass)
  82. .replace(/%iseditable%/gi, option.attr('data-is-editable') ? ''+o.mselectItemNotEditableClass+'' : '')
  83. .replace(/%isremovable%/i, option.attr('data-is-removable') ? ''+o.mselectItemNotRemovableClass+'' : '')
  84. .replace(/%label%/gi, option.html());
  85. });
  86. return str;
  87. })(),
  88. html = o.layout
  89. .replace(/%items%/gi, items)
  90. .replace(/%mselectListClass%/gi, o.mselectListClass)
  91. .replace(/%mselectButtonAddClass%/gi, o.mselectButtonAddClass)
  92. .replace(/%mselectButtonSaveClass%/gi, o.mselectButtonSaveClass)
  93. .replace(/%mselectButtonCancelClass%/gi, o.mselectButtonCancelClass)
  94. .replace(/%mselectItemsWrapperClass%/gi, o.mselectItemsWrapperClass)
  95. .replace(/%mselectInputContainerClass%/gi, o.mselectInputContainerClass)
  96. .replace(/%mselectInputClass%/gi, o.mselectInputClass)
  97. .replace(/%addText%/gi, o.addText)
  98. .replace(/%cancelText%/gi, o.cancelText)
  99. .replace(/%inputTitle%/gi, o.inputTitle),
  100. widget = $(html)
  101. .insertAfter(this)
  102. .on('change.mselectCheck', '[type=checkbox]', function() {
  103. var checkbox = $(this),
  104. index = checkbox.closest('.' + o.mselectListItemClass + '').index();
  105. select.find('option').eq(index).attr('selected', !!checkbox.attr('checked'));
  106. }),
  107. list = widget.find('.' + o.mselectItemsWrapperClass + ''),
  108. buttonAdd = widget.find('.' + o.mselectButtonAddClass + '')
  109. .on('click.mselectAdd', function(e) {
  110. e.preventDefault();
  111. o.toggleAddButton && buttonAdd.hide();
  112. container.show();
  113. input.focus();
  114. if (input.parents(o.mselectListClass).length) {
  115. list.scrollTop(list.height());
  116. }
  117. }),
  118. container = widget.find('.' + o.mselectInputContainerClass + ''),
  119. input = container.find('[type=text].' + o.mselectInputClass + '')
  120. .on('blur.mselectReset', function() {
  121. reset();
  122. })
  123. .on('keydown.mselectAddNewOption', function(e) {
  124. var c = e.keyCode;
  125. if (c == o.keyCodes.Enter || c == o.keyCodes.Esc) {
  126. e.preventDefault();
  127. c == o.keyCodes.Enter ? append(input.val()) : reset();
  128. }
  129. }),
  130. buttonSave = container.find('.' + o.mselectButtonSaveClass + '')
  131. .on('mousedown.mselectSave', function(e) {
  132. append(input.val());
  133. }),
  134. buttonCancel = container.find('.' + o.mselectButtonCancelClass + '')
  135. .on('mousedown.mdelectCancel', function(e) {
  136. input.val('');
  137. }),
  138. append = function(v) {
  139. // Add ability to define custom handler for adding new values
  140. if ($.isFunction(o.mselectInputSubmitCallback)) {
  141. o.mselectInputSubmitCallback(v, o);
  142. return;
  143. }
  144. // end of callback implementation
  145. $.each(typeof(o.parse) == 'function' ? o.parse(v) : [$.trim(v)], function(i, v) {
  146. var item;
  147. if (v && !select.children('[value="' + v + '"]').length) {
  148. item = $(o.item.replace(/%value%|%label%/gi, v)
  149. .replace(/%mselectDisabledClass%|%iseditable%|%isremovable%/gi,'')
  150. .replace(/%mselectListItemClass%/gi,o.mselectListItemClass))
  151. .find('[type=checkbox]')
  152. .attr('checked', true)
  153. .addClass(o.mselectCheckedClass)
  154. .end();
  155. list.children('.' + o.mselectListItemClass + '').length
  156. ? list.children('.' + o.mselectListItemClass + ':last').after(item)
  157. : list.prepend(item);
  158. select.append('<option value="' + v + '" selected="selected">' + v + '</option>');
  159. }
  160. });
  161. reset();
  162. list.scrollTop(list.height());
  163. },
  164. reset = function() {
  165. var ch = select.children();
  166. input.val('');
  167. container.hide();
  168. buttonAdd.show();
  169. list[list.children().length ? 'show' : 'hide']();
  170. if (ch.length >= size && !list.hasClass(o.mselectItemsWrapperOverflowClass)) {
  171. list.height(list.children('.' + o.mselectListItemClass + ':first')
  172. .outerHeight(true) * size)
  173. .addClass(o.mselectItemsWrapperOverflowClass);
  174. }
  175. };
  176. reset();
  177. }).end();
  178. };
  179. });