2023-01-11 21:45:41 +01:00
|
|
|
import {
|
|
|
|
isSelectElement,
|
|
|
|
isCheckboxOrRadioInputElement,
|
|
|
|
isTextInputElement,
|
|
|
|
isDateInputElement
|
|
|
|
} from '@utils';
|
2022-10-27 17:07:18 +02:00
|
|
|
import { ApplicationController } from './application_controller';
|
2023-01-11 21:45:41 +01:00
|
|
|
|
|
|
|
const AUTOSUBMIT_DEBOUNCE_DELAY = 500;
|
|
|
|
const AUTOSUBMIT_DATE_DEBOUNCE_DELAY = 5000;
|
2022-10-27 17:07:18 +02:00
|
|
|
|
|
|
|
export class AutosubmitController extends ApplicationController {
|
2023-01-11 21:45:41 +01:00
|
|
|
static targets = ['submitter'];
|
2022-10-27 17:07:18 +02:00
|
|
|
|
2023-01-11 21:45:41 +01:00
|
|
|
declare readonly submitterTarget: HTMLButtonElement | HTMLInputElement;
|
|
|
|
declare readonly hasSubmitterTarget: boolean;
|
2022-10-27 17:07:18 +02:00
|
|
|
|
2023-01-11 21:45:41 +01:00
|
|
|
#dateTimeChangedInputs = new WeakSet<HTMLInputElement>();
|
2022-11-04 12:22:39 +01:00
|
|
|
|
2023-01-11 21:45:41 +01:00
|
|
|
connect() {
|
|
|
|
this.on('input', (event) => this.onInput(event));
|
|
|
|
this.on('change', (event) => this.onChange(event));
|
|
|
|
this.on('blur', (event) => this.onBlur(event));
|
2022-11-04 12:22:39 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 21:45:41 +01:00
|
|
|
private onChange(event: Event) {
|
|
|
|
const target = event.target as HTMLInputElement;
|
|
|
|
if (target.disabled || target.hasAttribute('data-no-autosubmit')) return;
|
|
|
|
|
|
|
|
if (
|
|
|
|
isSelectElement(target) ||
|
|
|
|
isCheckboxOrRadioInputElement(target) ||
|
|
|
|
isTextInputElement(target)
|
|
|
|
) {
|
|
|
|
if (isDateInputElement(target)) {
|
|
|
|
if (target.value.trim() == '' || !isNaN(Date.parse(target.value))) {
|
|
|
|
this.#dateTimeChangedInputs.add(target);
|
|
|
|
this.debounce(this.submit, AUTOSUBMIT_DATE_DEBOUNCE_DELAY);
|
|
|
|
} else {
|
|
|
|
this.#dateTimeChangedInputs.delete(target);
|
|
|
|
this.cancelDebounce(this.submit);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.cancelDebounce(this.submit);
|
|
|
|
this.submit();
|
2023-01-06 17:53:20 +01:00
|
|
|
}
|
2023-01-11 21:45:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private onInput(event: Event) {
|
|
|
|
const target = event.target as HTMLInputElement;
|
|
|
|
if (target.disabled || target.hasAttribute('data-no-autosubmit')) return;
|
|
|
|
|
|
|
|
if (!isDateInputElement(target) && isTextInputElement(target)) {
|
|
|
|
this.debounce(this.submit, AUTOSUBMIT_DEBOUNCE_DELAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private onBlur(event: Event) {
|
|
|
|
const target = event.target as HTMLInputElement;
|
|
|
|
if (target.disabled || target.hasAttribute('data-no-autosubmit')) return;
|
|
|
|
|
|
|
|
if (isDateInputElement(target)) {
|
|
|
|
Promise.resolve().then(() => {
|
|
|
|
if (this.#dateTimeChangedInputs.has(target)) {
|
|
|
|
this.cancelDebounce(this.submit);
|
|
|
|
this.submit();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private submit() {
|
|
|
|
const submitter = this.hasSubmitterTarget ? this.submitterTarget : null;
|
|
|
|
const form =
|
|
|
|
submitter?.form ?? this.element.closest<HTMLFormElement>('form');
|
|
|
|
form?.requestSubmit(submitter);
|
2022-10-27 17:07:18 +02:00
|
|
|
}
|
|
|
|
}
|