Skip to content

Commit 2d91f78

Browse files
authored
Merge pull request #4491 from Laravel-Backpack/repeatable-field-focuses-on-first-input
[Feature] Repeatable field focuses on first focusable input
2 parents 7d0b88e + e4fa05d commit 2d91f78

File tree

1 file changed

+56
-9
lines changed

1 file changed

+56
-9
lines changed

src/resources/views/crud/form_content.blade.php

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)