From c6f0206b579fd5ef9341ee5f7e84b6416f490efe Mon Sep 17 00:00:00 2001 From: raviks789 Date: Wed, 4 Mar 2026 09:02:22 +0100 Subject: [PATCH 1/3] Completer.js: Trigger autosubmit on focus out for manual input if the not instrumented Ensure the form submits automatically when: - The completer is not part of term input or instrumented - The completer has the autosubmit dataset attribute - No suggestion is explicitly selected on manual input --- asset/js/widget/Completer.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/asset/js/widget/Completer.js b/asset/js/widget/Completer.js index a11548a3..b8070efd 100644 --- a/asset/js/widget/Completer.js +++ b/asset/js/widget/Completer.js @@ -6,6 +6,7 @@ define(["../notjQuery"], function ($) { constructor(input, instrumented = false) { this.input = input; this.instrumented = instrumented; + this.hasNotBeenCompleted = false; // Flag to identify if the input has been completed at least once. this.selectionStartInput = null; this.selectionActive = false; this.mouseSelectionActive = false; @@ -268,6 +269,7 @@ define(["../notjQuery"], function ($) { complete(input, value, data) { $(input).focus({ scripted: true }); + this.hasNotBeenCompleted = false; if (this.instrumented) { if (! Object.keys(data).length) { @@ -476,7 +478,7 @@ define(["../notjQuery"], function ($) { } onFocusOut(event) { - if (this.completedInput === null) { + if (this.completedInput === null && (this.instrumented || ! this.hasNotBeenCompleted)) { // If there are multiple instances of Completer bound to the same suggestion container // all of them try to handle the event. Though, only one of them is responsible and // that's the one which has a completed input set. @@ -492,12 +494,20 @@ define(["../notjQuery"], function ($) { && ! this.termSuggestions.contains(document.activeElement) ) { // Hide the suggestions if the user doesn't navigate them - if (input !== completedInput) { + if (completedInput !== null && input !== completedInput) { // Restore input if a suggestion lost focus this.suggest(completedInput, this.completedValue); } this.hideSuggestions(); + + // Autosubmit when the user leaves without selecting a suggestion on manual input. + // Only for non-instrumented mode — instrumented inputs (e.g. TermInput) handle + // autosubmit themselves via BaseInput.autoSubmit() with proper term data. + if (! this.instrumented && this.shouldAutoSubmit()) { + this.hasNotBeenCompleted = false; + $(input.form).trigger('submit', { submittedBy: input }); + } } }, 250); } @@ -712,6 +722,7 @@ define(["../notjQuery"], function ($) { onInput(event) { let input = event.target; + this.hasNotBeenCompleted = true; if (input.minLength > 0 && input.value.length < input.minLength) { return; From ee7139998c7526aa09393ec5c8bca1cdadca3ce0 Mon Sep 17 00:00:00 2001 From: raviks789 Date: Fri, 6 Mar 2026 13:04:45 +0100 Subject: [PATCH 2/3] fix: resolve review comments - rename property hasNotBeenCompleted to hasBeenManuallyChanged - Separate autosubmit logic from suggestionkiller --- asset/js/widget/Completer.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/asset/js/widget/Completer.js b/asset/js/widget/Completer.js index b8070efd..1fb85045 100644 --- a/asset/js/widget/Completer.js +++ b/asset/js/widget/Completer.js @@ -6,7 +6,7 @@ define(["../notjQuery"], function ($) { constructor(input, instrumented = false) { this.input = input; this.instrumented = instrumented; - this.hasNotBeenCompleted = false; // Flag to identify if the input has been completed at least once. + this.hasBeenManuallyChanged = false; // Flag to identify if the input has been manually changed. this.selectionStartInput = null; this.selectionActive = false; this.mouseSelectionActive = false; @@ -269,7 +269,7 @@ define(["../notjQuery"], function ($) { complete(input, value, data) { $(input).focus({ scripted: true }); - this.hasNotBeenCompleted = false; + this.hasBeenManuallyChanged = false; if (this.instrumented) { if (! Object.keys(data).length) { @@ -478,7 +478,18 @@ define(["../notjQuery"], function ($) { } onFocusOut(event) { - if (this.completedInput === null && (this.instrumented || ! this.hasNotBeenCompleted)) { + // Autosubmit when the user leaves the input without selecting a suggestion on manually changing the value. + // Only for non-instrumented mode — instrumented inputs (e.g. TermInput) handle + // autosubmit themselves via BaseInput.autoSubmit() with proper term data. + if (! this.instrumented && this.hasBeenManuallyChanged && this.shouldAutoSubmit()) { + this.hasBeenManuallyChanged = false; + let input = event.target; + setTimeout(() => { + $(input.form).trigger('submit', { submittedBy: input }); + }, 250); + } + + if (this.completedInput === null) { // If there are multiple instances of Completer bound to the same suggestion container // all of them try to handle the event. Though, only one of them is responsible and // that's the one which has a completed input set. @@ -494,20 +505,12 @@ define(["../notjQuery"], function ($) { && ! this.termSuggestions.contains(document.activeElement) ) { // Hide the suggestions if the user doesn't navigate them - if (completedInput !== null && input !== completedInput) { + if (input !== completedInput) { // Restore input if a suggestion lost focus this.suggest(completedInput, this.completedValue); } this.hideSuggestions(); - - // Autosubmit when the user leaves without selecting a suggestion on manual input. - // Only for non-instrumented mode — instrumented inputs (e.g. TermInput) handle - // autosubmit themselves via BaseInput.autoSubmit() with proper term data. - if (! this.instrumented && this.shouldAutoSubmit()) { - this.hasNotBeenCompleted = false; - $(input.form).trigger('submit', { submittedBy: input }); - } } }, 250); } @@ -722,7 +725,7 @@ define(["../notjQuery"], function ($) { onInput(event) { let input = event.target; - this.hasNotBeenCompleted = true; + this.hasBeenManuallyChanged = true; if (input.minLength > 0 && input.value.length < input.minLength) { return; From a195165ea86230f9c7295582c40024b721cbc9cd Mon Sep 17 00:00:00 2001 From: raviks789 Date: Fri, 6 Mar 2026 15:16:01 +0100 Subject: [PATCH 3/3] fix: autosubmit only if the suggestion is closed --- asset/js/widget/Completer.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/asset/js/widget/Completer.js b/asset/js/widget/Completer.js index 1fb85045..e1b0de4a 100644 --- a/asset/js/widget/Completer.js +++ b/asset/js/widget/Completer.js @@ -478,7 +478,7 @@ define(["../notjQuery"], function ($) { } onFocusOut(event) { - // Autosubmit when the user leaves the input without selecting a suggestion on manually changing the value. + // Autosubmit if the user leaves the input and the input has been manually changed. // Only for non-instrumented mode — instrumented inputs (e.g. TermInput) handle // autosubmit themselves via BaseInput.autoSubmit() with proper term data. if (! this.instrumented && this.hasBeenManuallyChanged && this.shouldAutoSubmit()) { @@ -486,7 +486,7 @@ define(["../notjQuery"], function ($) { let input = event.target; setTimeout(() => { $(input.form).trigger('submit', { submittedBy: input }); - }, 250); + }, 300); } if (this.completedInput === null) { @@ -511,6 +511,7 @@ define(["../notjQuery"], function ($) { } this.hideSuggestions(); + this.hasBeenManuallyChanged = true; } }, 250); } @@ -668,6 +669,7 @@ define(["../notjQuery"], function ($) { break; case 'Tab': suggestions = this.termSuggestions.querySelectorAll('[type="button"]'); + this.hasBeenManuallyChanged = false; if (suggestions.length === 1) { event.preventDefault(); let input = event.target; @@ -689,6 +691,7 @@ define(["../notjQuery"], function ($) { break; case 'Escape': if (this.hasSuggestions()) { + this.hasBeenManuallyChanged = true; this.hideSuggestions() event.preventDefault(); } @@ -696,6 +699,7 @@ define(["../notjQuery"], function ($) { break; case 'ArrowUp': suggestions = this.termSuggestions.querySelectorAll('[type="button"]'); + this.hasBeenManuallyChanged = false; if (suggestions.length) { event.preventDefault(); this.moveToSuggestion(true); @@ -704,6 +708,7 @@ define(["../notjQuery"], function ($) { break; case 'ArrowDown': suggestions = this.termSuggestions.querySelectorAll('[type="button"]'); + this.hasBeenManuallyChanged = false; if (suggestions.length) { event.preventDefault(); this.moveToSuggestion();