1 2function saas_init_bs_multiselect() { 3 jQuery( 'select[multiple], .filterable select, select.multiselect' ).not( '.multiselect-initialized' ).each( function( i ) { 4 5 const select = this; 6 const $select = jQuery( this ); 7 const field_classes_to_copy = $select.attr( 'data-field-classes-to-copy' ) || 'border theme-rounded-input'; 8 const popup_classes_to_copy = $select.attr( 'data-popup-classes-to-copy' ) || 'border theme-rounded-input-limited'; 9 10 const args = { 11 12 templates: { 13 button: '<button type="button" class="multiselect dropdown-toggle ' + field_classes_to_copy + '" data-bs-toggle="dropdown"><span class="multiselect-selected-text"></span></button>', 14 popupContainer: '<div class="multiselect-container dropdown-menu ' + popup_classes_to_copy + '"></div>', 15 filter: '<div class="multiselect-filter d-flex align-items-center"><i class="fas fa-sm fa-search text-muted"></i><input type="search" class="multiselect-search form-control" /></div>', 16 buttonGroup: '<div class="multiselect-buttons btn-group dropdown d-flex"></div>', 17 buttonGroupReset: '<button type="button" class="multiselect-reset btn btn-secondary btn-block"></button>', 18 option: '<button type="button" class="multiselect-option dropdown-item"></button>', 19 divider: '<div class="dropdown-divider"></div>', 20 optionGroup: '<button type="button" class="multiselect-group dropdown-item"></button>', 21 resetButton: '<div class="multiselect-reset text-center p-2"><button type="button" class="btn btn-sm btn-block btn-outline-secondary"></button></div>' 22 }, 23 includeSelectAllOption: true, 24 enableFiltering: false, 25 includeFilterClearBtn: true, 26 enableCaseInsensitiveFiltering: true, 27 onInitialized: function( select, container ) { 28 29 // Custom event 30 // $select.trigger( 'multiselect-initialized' ); 31 $select.get( 0 ).dispatchEvent( new CustomEvent( 'multiselect-initialized' ) ); 32 33 $select.addClass( 'multiselect-initialized' ); 34 35 // Re-init icons in newly rendered dropdown (search) 36 if ( typeof window.FontAwesome !== 'undefined' ) { 37 window.FontAwesome.dom.i2svg( { node: select.parentElement } ); 38 } 39 else { 40 setTimeout( function() { 41 if ( typeof window.FontAwesome !== 'undefined' ) { 42 window.FontAwesome.dom.i2svg( { node: select.parentElement } ); 43 } 44 }, 1000 ); 45 } 46 47 }, 48 onDropdownShow: function( event ) { 49 50 // Custom event 51 select.dispatchEvent( new CustomEvent( 'multiselect-open' ) ); 52 53 // Global flag 54 // window.moddse_multiselect_is_open = true; 55 56 // Temporarily disable the fontawesome dom change listener for performance while text searching in the list. 57 // Reenabled on onDropdownHide 58 // if ( typeof window.FontAwesome !== 'undefined' ) { 59 // window.FontAwesome.dom.unwatch(); 60 // } 61 62 }, 63 onDropdownHide: function( event ) { 64 65 // Global flag 66 // window.moddse_multiselect_is_open = false; 67 68 // Reenable the fontawesome dom change listener. 69 // if ( typeof window.FontAwesome !== 'undefined' ) { 70 // window.FontAwesome.dom.watch(); 71 // } 72 73 }, 74 onChange: function( option, checked, select ) { 75 76 // Trigger a native 'change' event on the actual select element 77 this.$select[0].dispatchEvent( new Event( 'change', { bubbles: true } ) ); 78 $select.trigger( 'multiselect-change', option ); 79 80 // Apply selection limit when applicable 81 if ( $select.data( 'max' ) ) { 82 83 const $options = $select.children( 'option' ); 84 const selected_options = $select.children( 'option:selected' ); 85 const max = $select.data( 'max' ); 86 87 // Disable all other checkboxes 88 if ( selected_options.length >= max ) { 89 const non_selected_options = $options.filter( function() { 90 return ! jQuery( this ).is( ':selected' ); 91 } ); 92 non_selected_options.each( function() { 93 const checkbox = jQuery( 'input[value="' + jQuery( this ).val() + '"]' ); 94 checkbox.prop( 'disabled', true ); 95 checkbox.closest( '.multiselect-option' ).addClass( 'disabled' ); 96 } ); 97 } 98 99 // Enable all checkboxes 100 else { 101 $options.each( function() { 102 const checkbox = jQuery( 'input[value="' + jQuery( this ).val() + '"]' ); 103 checkbox.prop( 'disabled', false ); 104 checkbox.closest( '.multiselect-option' ).removeClass( 'disabled' ); 105 } ); 106 } 107 108 } 109 110 }, 111 onSelectAll: function( options ) { 112 select.dispatchEvent( new Event( 'change', { bubbles: true } ) ); 113 $select.trigger( 'multiselect-change', options ); 114 }, 115 onDeselectAll: function(options) { 116 select.dispatchEvent( new Event( 'change', { bubbles: true } ) ); 117 $select.trigger( 'multiselect-change', options ); 118 }, 119 120 // Translations 121 allSelectedText: multiselect_ajax_object.translations.allSelectedText, 122 filterPlaceholder: multiselect_ajax_object.translations.filterPlaceholder, 123 nonSelectedText: multiselect_ajax_object.translations.nonSelectedText, 124 nSelectedText: multiselect_ajax_object.translations.nSelectedText, 125 resetText: multiselect_ajax_object.translations.resetText, 126 selectAllText: multiselect_ajax_object.translations.selectAllText 127 128 }; 129 130 if ( select.classList.contains( '-nosearch' ) ) { 131 args.enableFiltering = false;
132 args.enableCaseInsensitiveFiltering = false; 133 } 134 135 if ( $select.attr( 'data-nonSelectedText' ) ) { 136 args.nonSelectedText = $select.attr( 'data-nonSelectedText' ); 137 } 138 139 if ( $select.attr( 'data-allSelectedText' ) ) { 140 args.allSelectedText = $select.attr( 'data-allSelectedText' ); 141 } 142 143 if ( $select.attr( 'data-includeSelectAllOption' ) ) { 144 args.includeSelectAllOption = parseInt( $select.attr( 'data-includeSelectAllOption' ), 10 ); 145 } 146 147 // Customize the dropdown text relevant to the selections 148 if ( $select.attr( 'data-show-selected-number' ) && args.nonSelectedText ) { 149 args.buttonText = function( options, select ) { 150 const nonselectedtext = select[0].getAttribute( 'data-nonselectedtext' ); 151 const selected = options.length === 1 ? ' (' + options[0].label + ')' : options.length ? ' (' + options.length + ')' : ''; 152 return nonselectedtext + selected; 153 }; 154 } 155 156 // Add the multiple attr if it doesn't exist yet 157 if ( ! $select.attr( 'multiple' ) && ! $select.hasClass( '-single' ) ) { 158 $select.attr( 'multiple', 'multiple' ); 159 $select.find( 'option' ).prop( 'selected', false ); // Native non-multiple select has first option selected by default 160 } 161 162 // Keep a copy of the original element in memory, for when we need to re-initialize it after cloning. 163 const uid = '_' + Date.now() + '_' + i; 164 window['multiselect_originals'] = window['multiselect_originals'] || {}; 165 window['multiselect_originals'][ uid ] = $select.clone(); 166 $select.attr( 'data-uid', uid ); 167 168 // Init 169 $select.multiselect( args ); 170 171 }); 172} 173 174// Load the Bootstrap Multiselect library (once) when a multiselect is present, then init. 175// Runs on page load and again for content arriving via ajax template parts (e.g. the conditional-page swap), 176// where the first select may only appear after the initial load. 177function saas_ensure_bs_multiselect() { 178 179 if ( ! document.querySelector( 'select[multiple], .filterable select, .multiselect' ) ) { 180 return; 181 } 182 183 saas_load_jquery( function() { 184 185 const script_id = 'bootstrap-multiselect-lib-js'; 186 const existing = document.getElementById( script_id ); 187 188 // Library present and executed: init straight away. 189 if ( existing && typeof jQuery.fn.multiselect === 'function' ) { 190 saas_init_bs_multiselect(); 191 return; 192 } 193 194 // Library still loading (a previous call injected it): init once it lands. 195 if ( existing ) { 196 existing.addEventListener( 'load', saas_init_bs_multiselect ); 197 return; 198 } 199 200 const script = document.createElement( 'script' ); 201 document.body.appendChild( script ); 202 script.id = script_id; 203 script.onload = function() { 204 205 // Init on pageload 206 saas_init_bs_multiselect(); 207 208 // Reinit on GF validation error 209 jQuery( document ).bind( 'gform_post_render', saas_init_bs_multiselect ); 210 211 } 212 script.async = false; 213 script.src = multiselect_ajax_object.bootstrap_multiselect_lib; 214 215 } ); 216 217} 218 219saas_ensure_bs_multiselect(); 220document.body.addEventListener( 'ajax-template-loaded', saas_ensure_bs_multiselect );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.