Skip to content

Instantly share code, notes, and snippets.

@filiphlm
Created May 15, 2024 16:09
Show Gist options
  • Save filiphlm/e8cb4eeebcd26c2d6a3befd3efd330d3 to your computer and use it in GitHub Desktop.
Save filiphlm/e8cb4eeebcd26c2d6a3befd3efd330d3 to your computer and use it in GitHub Desktop.
/* eslint-disable func-style */
/* eslint-disable no-nested-ternary */
(function () {
'use strict';
if (!('submitter' in Event.prototype)) {
let submitterPrototype = window.Event.prototype;
if (!('SubmitEvent' in window && (submitterPrototype = window.SubmitEvent.prototype, !/Apple Computer/.test(navigator.vendor) || 'submitter' in submitterPrototype))) {
const submittersByForm = new WeakMap();
Object.defineProperty(submitterPrototype, 'submitter', {get() {
if (this.type === 'submit' && this.target instanceof HTMLFormElement) {
return submittersByForm.get(this.target);
}
return null;
}});
addEventListener('click', ( event ) => {
const target = event.target instanceof Element ?
event.target : event.target instanceof Node ?
event.target.parentElement : null,
submitter = target ? /** @type {HTMLButtonElement|HTMLInputElement} */(target.closest('button, input[type="submit"], input[type="image"]')) : null;
if (submitter && submitter.form) {
submittersByForm.set(submitter.form, submitter);
}
}, true);
}
}
/**
* FormData submitter polyfill
* Copyright 2023 Jon Jensen
* https://github.com/jenseng/formdata-submitter-polyfill
*/
try {
// @ts-expect-error: One-time check to see if the native FormData supports submitter
new window.FormData(document.createElement('form'), 'oh-no');
} catch (caught) {
return;
}
const FormDataPrototype = window.FormData,
Coords = Symbol(),
ImageButton = 'input[type="image"]';
/**
* @param {HTMLFormElement} form
* @param {HTMLButtonElement|HTMLInputElement} submitter
*/
function submitterFieldsInTreeOrder(form, submitter) {
let entries;
if (submitter.matches(ImageButton)) {
const coordinates = submitter[Coords] ?? {x: 0, y: 0},
prefix = submitter.name ? `${submitter.name}.` : '';
entries = [[`${prefix}x`, String(coordinates.x)], [`${prefix}y`, String(coordinates.y)]];
} else {
entries = submitter.name ? [[submitter.name, submitter.value]] : [];
}
const externalSubmitter = !form.contains(submitter),
container = document.createElement('span');
submitter.insertAdjacentElement('afterend', container);
for (const [name, value] of entries) {
const field = document.createElement('input');
field.type = 'hidden';
field.name = name;
field.value = String(value);
if (externalSubmitter) {
field.setAttribute('form', form.id);
}
container.insertAdjacentElement('beforeend', field);
}
submitter.insertAdjacentElement('afterend', container);
return container;
}
window.FormData = class extends FormDataPrototype {
constructor(...args) {
const [form, submitter] = args;
if (form !== void 0 && !(form instanceof HTMLFormElement)) {
throw new TypeError('Failed to construct "FormData": parameter 1 is not of type "HTMLFormElement"');
}
if (submitter !== null) {
if (!submitter.matches('button, input[type="submit"], input[type="image"]')) {
throw new TypeError('Failed to construct "FormData": The specified element is not a submit button.');
}
if (form && submitter.form !== form) {
throw new DOMException('Failed to construct "FormData": The specified element is not owned by this form element', 'NotFoundError');
}
}
if (form && submitter !== null) {
const {disabled} = submitter;
submitter.disabled = true;
try {
const container = submitterFieldsInTreeOrder(form, submitter);
super(form);
container.remove();
} finally {
submitter.disabled = disabled;
}
} else {
super(form);
}
}
};
addEventListener('click', (event) => {
const target = event.target instanceof Element
? event.target : event.target instanceof Node
? event.target.parentElement : null,
submitter = target && target.matches(ImageButton) ? /** @type {HTMLInputElement} */(target) : null;
if (submitter && submitter.form) {
event.target[Coords] = {x: event.offsetX, y: event.offsetY};
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment