1/** 2 * @file 3 * auto_submit.js 4 * 5 * Provides a "form auto-submit" feature for the Better Exposed Filters module. 6 */ 7 8(function ($, Drupal, once) { 9 10 /** 11 * To make a form auto submit, all you have to do is 3 things:. 12 * 13 * Use the "better_exposed_filters/auto_submit" js library. 14 * 15 * On gadgets, you want to auto-submit when changed, add the 16 * data-bef-auto-submit attribute. With FAPI, add: 17 * @code 18 * '#attributes' => array('data-bef-auto-submit' => ''), 19 * @endcode 20 * 21 * If you want to have auto-submit for every form element, add the 22 * data-bef-auto-submit-full-form to the form. With FAPI, add: 23 * @code 24 * '#attributes' => array('data-bef-auto-submit-full-form' => ''), 25 * @endcode 26 * 27 * If you want to exclude a field from the bef-auto-submit-full-form auto 28 * submission, add an attribute of data-bef-auto-submit-exclude to the form 29 * element. With FAPI, add: 30 * @code 31 * '#attributes' => array('data-bef-auto-submit-exclude' => ''), 32 * @endcode 33 * 34 * Finally, you have to identify which button you want clicked for autosubmit. 35 * The behavior of this button will be honored if it's ajax or not: 36 * @code 37 * '#attributes' => array('data-bef-auto-submit-click' => ''), 38 * @endcode 39 * 40 * Currently only 'select', 'radio', 'checkbox' and 'textfield' types are 41 * supported. We probably could use additional support for HTML5 input types. 42 */ 43 Drupal.behaviors.betterExposedFiltersAutoSubmit = { 44 attach: function (context, settings) { 45 // When exposed as a block, the form #attributes are moved from the form 46 // to the block element, thus the second selector. 47 // @see \Drupal\block\BlockViewBuilder::preRender 48 const selectors = 'form[data-bef-auto-submit-full-form], [data-bef-auto-submit-full-form] form, [data-bef-auto-submit]'; 49 50 $(selectors, context).addBack(selectors).find('input:text:not(.hasDatepicker), textarea').each(function () { 51 const $el = $(this); 52 const $valueLength = $el.val().length * 2; 53 54 $el[0].setSelectionRange($valueLength, $valueLength); 55 setFocus($el, $valueLength); 56 }); 57 58 function setFocus($el) { 59 const observer = new IntersectionObserver((entries) => { 60 61 entries.forEach(entry => { 62 if (entry.isIntersecting) { 63 const $lastTriggeredSelector = $(settings.bef_autosubmit_target).attr('data-drupal-selector'); 64 if ($el.attr('data-drupal-selector') && $el.attr('data-drupal-selector') === $lastTriggeredSelector) { 65 $el.focus(); 66 } 67 } 68 }); 69 }); 70 71 observer.observe($el.get(0)); 72 } 73 74 // The change event bubbles, so we only need to bind it to the outer form 75 // in case of a full form, or a single element when specified explicitly. 76 $(selectors, context).addBack(selectors).each(function (i, e) { 77 const $e = $(e); 78 // Store the current form. 79 let $needsAutoSubmit = $e; 80 81 // Retrieve the autosubmit delay for this particular form.
82 let autoSubmitDelay = 500; 83 if (e.hasAttribute('data-bef-auto-submit-delay')) { 84 autoSubmitDelay = $e.data('bef-auto-submit-delay'); 85 } 86 else if (!e.hasAttribute('data-bef-auto-submit-full-form')) { 87 // Find the container but skip checking if this element already is 88 // 'form[data-bef-auto-submit-full-form]'. 89 const $container = $e.closest('[data-bef-auto-submit-full-form]'); 90 if ($container.length && $container.get(0).hasAttribute('data-bef-auto-submit-delay')) { 91 $needsAutoSubmit = $container; 92 autoSubmitDelay = $container.data('bef-auto-submit-delay'); 93 } 94 } 95 96 // Ensure that have a delay. 97 autoSubmitDelay = autoSubmitDelay || 500; 98 // Separate debounce instance for date inputs change event. 99 let dateInputChangeDebounce = Drupal.debounce(triggerSubmit, autoSubmitDelay, false); 100 101 // Attach event listeners. 102 $(once('bef-auto-submit', $needsAutoSubmit)) 103 // On change, trigger the submit immediately unless it's a date 104 // input which emits change event as soon as the date value is 105 // valid, even if user is still typing. 106 .on('change', function (e) { 107 return e.target.type === 'date' 108 ? dateInputChangeDebounce(e) 109 : triggerSubmit(e); 110 }) 111 // On keyup, wait for a specified number of milliseconds before 112 // triggering autosubmit. Each new keyup event resets the timer. 113 .on('keyup', Drupal.debounce(triggerSubmit, autoSubmitDelay, false)); 114 }); 115 116 /** 117 * Triggers form autosubmit when conditions are right. 118 * 119 * - Checks first that the element that was the target of the triggering 120 * event is `:text` or `textarea`, but is not `.hasDatePicker`. 121 * - Checks that the keycode of the keyup was not in the list of ignored 122 * keys (navigation keys etc.). 123 * 124 * @param {object} e - The triggering event. 125 */ 126 function triggerSubmit(e) { 127 // e.keyCode: key. 128 const ignoredKeyCodes = [ 129 16, // Shift. 130 17, // Ctrl. 131 18, // Alt. 132 20, // Caps lock. 133 33, // Page up. 134 34, // Page down. 135 35, // End. 136 36, // Home. 137 37, // Left arrow. 138 38, // Up arrow. 139 39, // Right arrow. 140 40, // Down arrow. 141 9, // Tab. 142 13, // Enter. 143 27, // Esc. 144 ]; 145 146 // Triggering element. 147 const $target = $(e.target); 148 const $submit = $target.closest('form').find('[data-bef-auto-submit-click]'); 149 150 // Don't submit on changes to excluded elements,submit elements, or select2 autocomplete. 151 if ($target.is('[data-bef-auto-submit-exclude], :submit, .select2-search__field, .chosen-search-input')) { 152 return true; 153 } 154 155 // Submit only if this is a non-datepicker textfield and if the 156 // incoming keycode is not one of the excluded values, and it has a 157 // minimum character length. 158 let textfieldMinimumLength = $target.closest('form').data('bef-auto-submit-minimum-length') || 1; 159 let inputTextLength = $target.val().length; 160 let textfieldHasMinimumLength = ($target.is(':text:not(.hasDatepicker), textarea') && inputTextLength >= textfieldMinimumLength) || $target.is('[type="checkbox"], [type="radio"]'); 161 if ( 162 (textfieldHasMinimumLength || inputTextLength === 0) 163 && $.inArray(e.keyCode, ignoredKeyCodes) === -1 164 && !e.altKey 165 && !e.ctrlKey 166 && !e.shiftKey 167 ) { 168 $submit.click(); 169 } 170 // Only trigger submit if a change was the trigger (no keyup). 171 else if (e.type === 'change') { 172 let target = $target.is(':text:not(.hasDatepicker), textarea'); 173 if (target && textfieldHasMinimumLength) { 174 $submit.click(); 175 } 176 else if (!target) { 177 $submit.click(); 178 } 179 } 180 181 settings.bef_autosubmit_target = $target; 182 } 183 }, 184 }; 185 186}(jQuery, Drupal, once));
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.