@@ -48,6 +48,52 @@ function initializeFieldsWithJavascript(container) {
4848 });
4949 }
5050
51+ /* *
52+ * Auto-discover first focusable input
53+ * @param {jQuery} form
54+ * @return {jQuery}
55+ */
56+ function getFirstFocusableField (form ) {
57+ return form .find (' input, select, textarea, button' )
58+ .not (' .close' )
59+ .not (' [disabled]' )
60+ .filter (' :visible:first' );
61+ }
62+
63+ /* *
64+ *
65+ * @param {jQuery} firstField
66+ */
67+ function triggerFocusOnFirstInputField (firstField ) {
68+ if (firstField .hasClass (' select2-hidden-accessible' )) {
69+ return handleFocusOnSelect2Field (firstField);
70+ }
71+
72+ firstField .trigger (' focus' );
73+ }
74+
75+ /* *
76+ * 1- Make sure no other select2 input is open in other field to focus on the right one
77+ * 2- Check until select2 is initialized
78+ * 3- Open select2
79+ *
80+ * @param {jQuery} firstField
81+ */
82+ function handleFocusOnSelect2Field (firstField ){
83+ $ (' .select2-search__field' ).remove ();
84+ firstField .select2 (' open' );
85+ }
86+
87+ /*
88+ * Hacky fix for a bug in select2 with jQuery 3.6.0's new nested-focus "protection"
89+ * see: https://github.com/select2/select2/issues/5993
90+ * see: https://github.com/jquery/jquery/issues/4382
91+ *
92+ */
93+ $ (document ).on (' select2:open' , () => {
94+ document .querySelector (' .select2-search__field' ).focus ();
95+ });
96+
5197 jQuery (' document' ).ready (function ($ ){
5298
5399 // trigger the javascript for all fields that have their js defined in a separate method
@@ -109,19 +155,21 @@ function preventUnload(event) {
109155 });
110156 @endphp
111157
158+ let focusField;
159+
112160 @if ($focusField )
113161 @php
114162 $focusFieldName = isset ($focusField [' value' ]) && is_iterable ($focusField [' value' ]) ? $focusField [' name' ] . ' []' : $focusField [' name' ];
115163 @endphp
116- window . focusField = $ (' [name="{{ $focusFieldName } } "]' ).eq (0 ),
164+ focusField = $ (' [name="{{ $focusFieldName } } "]' ).eq (0 );
117165 @else
118- var focusField = $ (' form' ). find ( ' input, textarea, select ' ). not ( ' [type="hidden"] ' ). eq ( 0 ),
166+ focusField = getFirstFocusableField ( $ (' form' ));
119167 @endif
120168
121- fieldOffset = focusField .offset ().top ,
122- scrollTolerance = $ (window ).height () / 2 ;
169+ const fieldOffset = focusField .offset ().top ;
170+ const scrollTolerance = $ (window ).height () / 2 ;
123171
124- focusField . trigger ( ' focus ' );
172+ triggerFocusOnFirstInputField (focusField );
125173
126174 if ( fieldOffset > scrollTolerance ){
127175 $ (' html, body' ).animate ({scrollTop: (fieldOffset - 30 )});
@@ -143,22 +191,22 @@ function preventUnload(event) {
143191 $ (' [name="' + normalizedProperty + ' []"]' ) :
144192 $ (' [name="' + normalizedProperty + ' "]' ),
145193 container = field .parents (' .form-group' );
146-
194+
147195 // iterate the inputs to add invalid classes to fields and red text to the field container.
148196 container .children (' input, textarea, select' ).each (function () {
149197 let containerField = $ (this );
150198 // add the invalida class to the field.
151199 containerField .addClass (' is-invalid' );
152200 // get field container
153201 let container = containerField .parent (' .form-group' );
154-
202+
155203 // if container is a repeatable group we don't want to add red text to the whole group,
156204 // we only want to add it to the fields that have errors inside that repeatable.
157205 if (! container .hasClass (' repeatable-group' )){
158206 container .addClass (' text-danger' );
159207 }
160208 });
161-
209+
162210 $ .each (messages, function (key , msg ){
163211 // highlight the input that errored
164212 var row = $ (' <div class="invalid-feedback d-block">' + msg + ' </div>' );
@@ -182,7 +230,6 @@ function preventUnload(event) {
182230 if (window .location .hash ) {
183231 $ (" input[name='_current_tab']" ).val (window .location .hash .substr (1 ));
184232 }
185-
186233 });
187234 </script >
188235
0 commit comments