bootstrap-selectsplitter.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. +function ($) {
  2. 'use strict';
  3. // CLASS DEFINITION
  4. // ===============================
  5. // NB: only user input triggers event change on SELECT.
  6. var SelectSplitter = function(element, options) {
  7. this.init('selectsplitter', element, options);
  8. };
  9. SelectSplitter.DEFAULTS = {
  10. template:
  11. '<div class="row" data-selectsplitter-wrapper-selector>' +
  12. '<div class="col-xs-12 col-sm-6">' +
  13. '<select class="form-control" data-selectsplitter-firstselect-selector></select>' +
  14. '</div>' +
  15. ' <!-- Add the extra clearfix for only the required viewport -->' +
  16. '<div class="clearfix visible-xs-block"></div>' +
  17. '<div class="col-xs-12 col-sm-6">' +
  18. '<select class="form-control" data-selectsplitter-secondselect-selector></select>' +
  19. '</div>' +
  20. '</div>'
  21. };
  22. /* Note: Est appelé par la fonction définie en var */
  23. SelectSplitter.prototype.init = function (type, element, options) {
  24. // Initial variables.
  25. var self = this;
  26. self.type = type;
  27. self.$element = $(element);
  28. self.$element.hide();
  29. self.options = $.extend( {}, SelectSplitter.DEFAULTS, options);
  30. // Get categoryParent data from $element's OPTGROUP.
  31. self.fullCategoryList = {};
  32. var optgroupCount = 0;
  33. var longestOptionCount = 0;
  34. self.$element.find('optgroup').each(function() {
  35. self.fullCategoryList[$(this).attr('label')] = {};
  36. var $that = $(this);
  37. var currentOptionCount = 0;
  38. $(this).find('option').each(function() {
  39. self.fullCategoryList[$that.attr('label')][$(this).attr('value')] = $(this).text();
  40. currentOptionCount++;
  41. });
  42. if (currentOptionCount > longestOptionCount) { longestOptionCount = currentOptionCount ;}
  43. optgroupCount++;
  44. });
  45. // Get OPTIONS for $firstSelect.
  46. var optionsHtml = '';
  47. for (var key in self.fullCategoryList) {
  48. if (self.fullCategoryList.hasOwnProperty(key)) {
  49. optionsHtml = optionsHtml + '<option>' + key + '</option>';
  50. }
  51. }
  52. // Add template.
  53. self.$element.after(self.options.template);
  54. // Define selected elements.
  55. self.$wrapper = self.$element.next('div[data-selectsplitter-wrapper-selector]'); // improved by keenthemes
  56. self.$firstSelect = $('select[data-selectsplitter-firstselect-selector]', self.$wrapper); // improved by keenthemes
  57. self.$secondSelect = $('select[data-selectsplitter-secondselect-selector]', self.$wrapper); // improved by keenthemes
  58. // Define $firstSelect and $secondSelect size attribute
  59. var selectSize = Math.max(optgroupCount, longestOptionCount);
  60. selectSize = Math.min(selectSize, 10);
  61. if (self.options.selectSize) {
  62. selectSize = self.options.selectSize; // improved by keenthemes
  63. }
  64. self.$firstSelect.attr('size', selectSize);
  65. self.$secondSelect.attr('size', selectSize);
  66. // Fill $firstSelect with OPTIONS
  67. self.$firstSelect.append(optionsHtml);
  68. // Define events.
  69. self.$firstSelect.on('change', $.proxy(self.updateParentCategory, self));
  70. self.$secondSelect.on('change', $.proxy(self.updateChildCategory, self));
  71. // Define main variables.
  72. self.$selectedOption = '';
  73. self.currentParentCategory = '';
  74. self.currentChildCategory = '';
  75. // Takes in consideration whether an option is already selected before initialization.
  76. // Note: .val() always returns the last value if SELECT is new. Hence cannot use .val() at init.
  77. // Note2: find(option:selected) retourne toujours une OPTION même lors du premier affichage.
  78. if ( self.$element.find('option[selected=selected]').length) {
  79. self.$selectedOption = self.$element.find('option[selected=selected]');
  80. self.currentParentCategory = self.$selectedOption.closest('optgroup').attr('label');
  81. self.currentChildCategory = self.$selectedOption.attr('value');
  82. self.$firstSelect.find('option:contains('+ self.currentParentCategory +')').attr('selected', 'selected');
  83. self.$firstSelect.trigger('change');
  84. }
  85. };
  86. SelectSplitter.prototype.updateParentCategory = function () {
  87. var self = this;
  88. // Update main variables.
  89. self.currentParentCategory = self.$firstSelect.val();
  90. self.$secondSelect.empty();
  91. // Définit la liste de I pour les icônes à afficher en fonction de la page.
  92. var optionsHtml = '';
  93. for (var key in self.fullCategoryList[self.currentParentCategory]) {
  94. if (self.fullCategoryList[self.currentParentCategory].hasOwnProperty(key)) {
  95. optionsHtml = optionsHtml + '<option value="' + key + '">' +
  96. self.fullCategoryList[self.currentParentCategory][key] +
  97. '</option>';
  98. }
  99. }
  100. self.$secondSelect.append(optionsHtml);
  101. if ( self.$selectedOption ) {
  102. self.$secondSelect.find( 'option[value=' + self.$selectedOption.attr('value') + ']' ).attr('selected', 'selected');
  103. }
  104. };
  105. SelectSplitter.prototype.updateChildCategory = function (event) {
  106. var self = this;
  107. // Update main variables.
  108. self.currentChildCategory = $(event.target).val(); // Note: event.target returns the SELECT, hence we must use val().
  109. // Remove selected items in $element SELECT, if any.
  110. self.$element.find('option[selected=selected]').removeAttr('selected');
  111. // Add selected attribute to the new selected OPTION.
  112. self.$element.find('option[value=' + self.currentChildCategory + ']').attr('selected', 'selected'); // Note: Adding attr also updates val().
  113. self.$element.trigger('change'); // Required for external plugins.
  114. self.$selectedOption = self.$element.find('option[selected=selected]');
  115. };
  116. SelectSplitter.prototype.destroy = function () {
  117. var self = this;
  118. self.$wrapper.remove();
  119. self.$element.removeData(self.type);
  120. self.$element.show();
  121. };
  122. // PLUGIN DEFINITION
  123. // =========================
  124. function Plugin(option) {
  125. return this.each(function() {
  126. var $this = $(this);
  127. var data = $this.data('selectsplitter');
  128. var options = typeof option === 'object' && option;
  129. if (!data && option == 'destroy') { return; }
  130. if (!data) { $this.data('selectsplitter', ( data = new SelectSplitter(this, options) ) ); }
  131. if (typeof option == 'string') { data[option](); }
  132. });
  133. }
  134. $.fn.selectsplitter = Plugin;
  135. /* http://stackoverflow.com/questions/10525600/what-is-the-purpose-of-fn-foo-constructor-foo-in-twitter-bootstrap-js */
  136. $.fn.selectsplitter.Constructor = SelectSplitter;
  137. }(jQuery);