|
@@ -1,12 +1,3 @@ |
|
|
/** |
|
|
|
|
|
* Type for valid field elements. |
|
|
|
|
|
*/ |
|
|
|
|
|
export type HTMLFieldElement |
|
|
|
|
|
= HTMLInputElement |
|
|
|
|
|
| HTMLButtonElement |
|
|
|
|
|
| HTMLSelectElement |
|
|
|
|
|
| HTMLTextAreaElement |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Line ending. |
|
|
* Line ending. |
|
|
*/ |
|
|
*/ |
|
@@ -25,84 +16,6 @@ export enum LineEnding { |
|
|
CRLF = '\r\n', |
|
|
CRLF = '\r\n', |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Type for valid submitter elements. |
|
|
|
|
|
* |
|
|
|
|
|
* Only the `<button>` and `<input>` elements can be submitter elements. |
|
|
|
|
|
*/ |
|
|
|
|
|
export type HTMLSubmitterElement |
|
|
|
|
|
= HTMLButtonElement |
|
|
|
|
|
| HTMLInputElement |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a `<textarea>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetTextAreaValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Line ending used for the element's value. |
|
|
|
|
|
*/ |
|
|
|
|
|
lineEndings?: LineEnding, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a `<select>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetSelectValueOptions = {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input type="checkbox">` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputCheckboxFieldValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Should we consider the `checked` attribute of checkboxes with no `value` attributes instead of the default value |
|
|
|
|
|
* "on" when checked? |
|
|
|
|
|
* |
|
|
|
|
|
* This forces the field to get the `false` value when unchecked. |
|
|
|
|
|
*/ |
|
|
|
|
|
booleanValuelessCheckbox?: true, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input type="radio">` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputRadioFieldValueOptions = {} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input type="file">` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputFileFieldValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Should we retrieve the `files` attribute of file inputs instead of the currently selected file names? |
|
|
|
|
|
*/ |
|
|
|
|
|
getFileObjects?: true, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputFieldValueOptions |
|
|
|
|
|
= GetInputCheckboxFieldValueOptions |
|
|
|
|
|
& GetInputFileFieldValueOptions |
|
|
|
|
|
& GetInputRadioFieldValueOptions |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetFieldValueOptions |
|
|
|
|
|
= GetTextAreaValueOptions |
|
|
|
|
|
& GetSelectValueOptions |
|
|
|
|
|
& GetInputFieldValueOptions |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting form values. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetFormValuesOptions = GetFieldValueOptions & { |
|
|
|
|
|
/** |
|
|
|
|
|
* The element that triggered the submission of the form. |
|
|
|
|
|
*/ |
|
|
|
|
|
submitter?: HTMLSubmitterElement, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Checks if an element can hold a field value. |
|
|
* Checks if an element can hold a field value. |
|
|
* @param el - The element. |
|
|
* @param el - The element. |
|
@@ -123,11 +36,32 @@ export const isFormFieldElement = (el: HTMLElement) => { |
|
|
return Boolean(inputEl.name) |
|
|
return Boolean(inputEl.name) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a `<textarea>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetTextAreaValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Line ending used for the element's value. |
|
|
|
|
|
*/ |
|
|
|
|
|
lineEndings?: LineEnding, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Gets the value of a `<textarea>` element. |
|
|
|
|
|
* @param textareaEl - The element. |
|
|
|
|
|
* @param options - The options. |
|
|
|
|
|
* @returns Value of the textarea element. |
|
|
|
|
|
*/ |
|
|
const getTextAreaFieldValue = (textareaEl: HTMLTextAreaElement, options = {} as GetTextAreaValueOptions) => { |
|
|
const getTextAreaFieldValue = (textareaEl: HTMLTextAreaElement, options = {} as GetTextAreaValueOptions) => { |
|
|
const { lineEndings = LineEnding.CRLF, } = options |
|
|
const { lineEndings = LineEnding.CRLF, } = options |
|
|
return textareaEl.value.replace(/\n/g, lineEndings) |
|
|
return textareaEl.value.replace(/\n/g, lineEndings) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a `<select>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetSelectValueOptions = {} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of a `<select>` element. |
|
|
* Gets the value of a `<select>` element. |
|
|
* @param selectEl - The element. |
|
|
* @param selectEl - The element. |
|
@@ -144,20 +78,15 @@ const getSelectFieldValue = (selectEl: HTMLSelectElement, options = {} as GetSel |
|
|
return selectEl.value |
|
|
return selectEl.value |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Type for an `<input type="checkbox">` element. |
|
|
|
|
|
*/ |
|
|
|
|
|
export type HTMLInputCheckboxElement = HTMLInputElement & { type: 'checkbox' } |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Type for an `<input type="radio">` element. |
|
|
* Type for an `<input type="radio">` element. |
|
|
*/ |
|
|
*/ |
|
|
export type HTMLInputRadioElement = HTMLInputElement & { type: 'radio' } |
|
|
export type HTMLInputRadioElement = HTMLInputElement & { type: 'radio' } |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Type for an `<input type="file">` element. |
|
|
|
|
|
|
|
|
* Options for getting an `<input type="radio">` element field value. |
|
|
*/ |
|
|
*/ |
|
|
export type HTMLInputFileElement = HTMLInputElement & { type: 'file' } |
|
|
|
|
|
|
|
|
type GetInputRadioFieldValueOptions = {} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of an `<input type="radio">` element. |
|
|
* Gets the value of an `<input type="radio">` element. |
|
@@ -174,13 +103,35 @@ const getInputRadioFieldValue = (inputEl: HTMLInputRadioElement, options = {} as |
|
|
} |
|
|
} |
|
|
return null |
|
|
return null |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Type for an `<input type="checkbox">` element. |
|
|
|
|
|
*/ |
|
|
|
|
|
export type HTMLInputCheckboxElement = HTMLInputElement & { type: 'checkbox' } |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input type="checkbox">` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputCheckboxFieldValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Should we consider the `checked` attribute of checkboxes with no `value` attributes instead of the default value |
|
|
|
|
|
* "on" when checked? |
|
|
|
|
|
* |
|
|
|
|
|
* This forces the field to get the `false` value when unchecked. |
|
|
|
|
|
*/ |
|
|
|
|
|
booleanValuelessCheckbox?: true, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of an `<input type="checkbox">` element. |
|
|
* Gets the value of an `<input type="checkbox">` element. |
|
|
* @param inputEl - The element. |
|
|
* @param inputEl - The element. |
|
|
* @param options - The options. |
|
|
* @param options - The options. |
|
|
* @returns Value of the input element. |
|
|
* @returns Value of the input element. |
|
|
*/ |
|
|
*/ |
|
|
const getInputCheckboxFieldValue = (inputEl: HTMLInputCheckboxElement, options = {} as GetInputCheckboxFieldValueOptions) => { |
|
|
|
|
|
|
|
|
const getInputCheckboxFieldValue = ( |
|
|
|
|
|
inputEl: HTMLInputCheckboxElement, |
|
|
|
|
|
options = {} as GetInputCheckboxFieldValueOptions |
|
|
|
|
|
) => { |
|
|
const checkedValue = inputEl.getAttribute('value') |
|
|
const checkedValue = inputEl.getAttribute('value') |
|
|
if (checkedValue !== null) { |
|
|
if (checkedValue !== null) { |
|
|
if (inputEl.checked) { |
|
|
if (inputEl.checked) { |
|
@@ -197,6 +148,21 @@ const getInputCheckboxFieldValue = (inputEl: HTMLInputCheckboxElement, options = |
|
|
return null |
|
|
return null |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Type for an `<input type="file">` element. |
|
|
|
|
|
*/ |
|
|
|
|
|
export type HTMLInputFileElement = HTMLInputElement & { type: 'file' } |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input type="file">` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputFileFieldValueOptions = { |
|
|
|
|
|
/** |
|
|
|
|
|
* Should we retrieve the `files` attribute of file inputs instead of the currently selected file names? |
|
|
|
|
|
*/ |
|
|
|
|
|
getFileObjects?: true, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of an `<input type="file">` element. |
|
|
* Gets the value of an `<input type="file">` element. |
|
|
* @param inputEl - The element. |
|
|
* @param inputEl - The element. |
|
@@ -204,7 +170,7 @@ const getInputCheckboxFieldValue = (inputEl: HTMLInputCheckboxElement, options = |
|
|
* @returns Value of the input element. |
|
|
* @returns Value of the input element. |
|
|
*/ |
|
|
*/ |
|
|
const getInputFileFieldValue = (inputEl: HTMLInputFileElement, options = {} as GetInputFileFieldValueOptions) => { |
|
|
const getInputFileFieldValue = (inputEl: HTMLInputFileElement, options = {} as GetInputFileFieldValueOptions) => { |
|
|
const { files } = inputEl |
|
|
|
|
|
|
|
|
const { files, multiple } = inputEl |
|
|
if ((files as unknown) === null) { |
|
|
if ((files as unknown) === null) { |
|
|
return null |
|
|
return null |
|
|
} |
|
|
} |
|
@@ -212,15 +178,20 @@ const getInputFileFieldValue = (inputEl: HTMLInputFileElement, options = {} as G |
|
|
return files |
|
|
return files |
|
|
} |
|
|
} |
|
|
const filesArray = Array.from(files as FileList) |
|
|
const filesArray = Array.from(files as FileList) |
|
|
if (filesArray.length > 1) { |
|
|
|
|
|
|
|
|
if (multiple) { |
|
|
return filesArray.map(f => f.name) |
|
|
return filesArray.map(f => f.name) |
|
|
} |
|
|
} |
|
|
if (filesArray.length === 1) { |
|
|
|
|
|
return filesArray[0].name |
|
|
|
|
|
} |
|
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
return filesArray[0].name || '' |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting an `<input>` element field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetInputFieldValueOptions |
|
|
|
|
|
= GetInputCheckboxFieldValueOptions |
|
|
|
|
|
& GetInputFileFieldValueOptions |
|
|
|
|
|
& GetInputRadioFieldValueOptions |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of an `<input>` element. |
|
|
* Gets the value of an `<input>` element. |
|
|
* @param inputEl - The element. |
|
|
* @param inputEl - The element. |
|
@@ -228,7 +199,7 @@ const getInputFileFieldValue = (inputEl: HTMLInputFileElement, options = {} as G |
|
|
* @returns Value of the input element. |
|
|
* @returns Value of the input element. |
|
|
*/ |
|
|
*/ |
|
|
const getInputFieldValue = (inputEl: HTMLInputElement, options = {} as GetInputFieldValueOptions) => { |
|
|
const getInputFieldValue = (inputEl: HTMLInputElement, options = {} as GetInputFieldValueOptions) => { |
|
|
switch (inputEl.type) { |
|
|
|
|
|
|
|
|
switch (inputEl.type.toLowerCase()) { |
|
|
case 'checkbox': |
|
|
case 'checkbox': |
|
|
return getInputCheckboxFieldValue(inputEl as HTMLInputCheckboxElement, options) |
|
|
return getInputCheckboxFieldValue(inputEl as HTMLInputCheckboxElement, options) |
|
|
case 'radio': |
|
|
case 'radio': |
|
@@ -241,6 +212,14 @@ const getInputFieldValue = (inputEl: HTMLInputElement, options = {} as GetInputF |
|
|
return inputEl.value |
|
|
return inputEl.value |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting a field value. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetFieldValueOptions |
|
|
|
|
|
= GetTextAreaValueOptions |
|
|
|
|
|
& GetSelectValueOptions |
|
|
|
|
|
& GetInputFieldValueOptions |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the value of a field element. |
|
|
* Gets the value of a field element. |
|
|
* @param el - The field element. |
|
|
* @param el - The field element. |
|
@@ -248,7 +227,7 @@ const getInputFieldValue = (inputEl: HTMLInputElement, options = {} as GetInputF |
|
|
* @returns Value of the field element. |
|
|
* @returns Value of the field element. |
|
|
*/ |
|
|
*/ |
|
|
export const getFieldValue = (el: HTMLElement, options = {} as GetFieldValueOptions) => { |
|
|
export const getFieldValue = (el: HTMLElement, options = {} as GetFieldValueOptions) => { |
|
|
switch (el.tagName) { |
|
|
|
|
|
|
|
|
switch (el.tagName.toUpperCase()) { |
|
|
case 'TEXTAREA': |
|
|
case 'TEXTAREA': |
|
|
return getTextAreaFieldValue(el as HTMLTextAreaElement, options) |
|
|
return getTextAreaFieldValue(el as HTMLTextAreaElement, options) |
|
|
case 'SELECT': |
|
|
case 'SELECT': |
|
@@ -259,7 +238,7 @@ export const getFieldValue = (el: HTMLElement, options = {} as GetFieldValueOpti |
|
|
break |
|
|
break |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const fieldEl = el as HTMLFieldElement |
|
|
|
|
|
|
|
|
const fieldEl = el as HTMLElement & { value?: unknown } |
|
|
return fieldEl.value || null |
|
|
return fieldEl.value || null |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -280,6 +259,16 @@ export const isNamedEnabledFormFieldElement = (el: HTMLElement) => { |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Options for getting form values. |
|
|
|
|
|
*/ |
|
|
|
|
|
type GetFormValuesOptions = GetFieldValueOptions & { |
|
|
|
|
|
/** |
|
|
|
|
|
* The element that triggered the submission of the form. |
|
|
|
|
|
*/ |
|
|
|
|
|
submitter?: HTMLElement, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Gets the values of all the fields within the form through accessing the DOM nodes. |
|
|
* Gets the values of all the fields within the form through accessing the DOM nodes. |
|
|
* @param form - The form. |
|
|
* @param form - The form. |
|
@@ -290,8 +279,8 @@ const getFormValues = (form: HTMLFormElement, options = {} as GetFormValuesOptio |
|
|
if (!form) { |
|
|
if (!form) { |
|
|
throw new TypeError('Invalid form element.') |
|
|
throw new TypeError('Invalid form element.') |
|
|
} |
|
|
} |
|
|
const formElements = form.elements as unknown as Record<string | number, HTMLFieldElement> |
|
|
|
|
|
const allFormFieldElements = Object.entries<HTMLFieldElement>(formElements) |
|
|
|
|
|
|
|
|
const formElements = form.elements as unknown as Record<string | number, HTMLElement> |
|
|
|
|
|
const allFormFieldElements = Object.entries<HTMLElement>(formElements) |
|
|
const indexedNamedEnabledFormFieldElements = allFormFieldElements.filter(([k, el]) => ( |
|
|
const indexedNamedEnabledFormFieldElements = allFormFieldElements.filter(([k, el]) => ( |
|
|
!isNaN(Number(k)) |
|
|
!isNaN(Number(k)) |
|
|
&& isNamedEnabledFormFieldElement(el) |
|
|
&& isNamedEnabledFormFieldElement(el) |
|
@@ -328,7 +317,7 @@ const getFormValues = (form: HTMLFormElement, options = {} as GetFormValuesOptio |
|
|
{} as any |
|
|
{} as any |
|
|
) |
|
|
) |
|
|
if (Boolean(options.submitter as unknown)) { |
|
|
if (Boolean(options.submitter as unknown)) { |
|
|
const submitter = options.submitter as HTMLSubmitterElement |
|
|
|
|
|
|
|
|
const submitter = options.submitter as HTMLElement & { name: string, value: unknown } |
|
|
if (submitter.name.length > 0) { |
|
|
if (submitter.name.length > 0) { |
|
|
return { |
|
|
return { |
|
|
...fieldValues, |
|
|
...fieldValues, |
|
|