Support multiple submit buttons in Active Storage forms#33413
Conversation
|
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @rafaelfranca (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review. Please see the contribution instructions for more information. |
There was a problem hiding this comment.
activestorage.js doesn't depend on rails-ujs so we can't rely on help from it. Even if we could, those "private" expando properties aren't meant to be accessed directly.
Maybe there's an easier way to track which submit button was clicked? Something like:
let button = findElement(form, "input[type=submit]:active, input[type=submit]")(untested!)
There was a problem hiding this comment.
Yes, thats understandable.
|
Not being able to get the button that actually submitted a form, is a known shortcoming of the form being the Unfortunately its also not as simple as using let button = findElement(form, "input[type=submit]:active, input[type=submit]")I made it work another way (see latest commit). Guess that |
1c88478 to
af1dd2e
Compare
af1dd2e to
c0d949d
Compare
Can you commit your source changes to |
3971eca to
c9ee0b8
Compare
Added the changes there too. |
There was a problem hiding this comment.
We can't rely Turbolinks events since not all apps use it. I'd add a new click listener here:
rails/activestorage/app/javascript/activestorage/ujs.js
Lines 10 to 11 in ba1dab1
The handler can check if the event.target is a submit button and record the last clicked button in a WeakMap using the button's form as the key.
My initial approach was to add the event listener into the |
There was a problem hiding this comment.
This won't handle clicks on dynamically inserted elements (ajax loaded content, Turbolinks page change, etc).
|
I think this will work, and avoids the need to handle --- a/activestorage/app/javascript/activestorage/ujs.js
+++ b/activestorage/app/javascript/activestorage/ujs.js
@@ -30,6 +30,7 @@ function handleFormSubmissionEvent(event) {
return
}
+ const button = findActiveSubmitButton(form)
const controller = new DirectUploadsController(form)
const { inputs } = controller
@@ -42,14 +43,14 @@ function handleFormSubmissionEvent(event) {
if (error) {
inputs.forEach(enable)
} else {
- submitForm(form)
+ submitForm(form, button)
}
})
}
}
-function submitForm(form) {
- let button = findElement(form, "input[type=submit]")
+function submitForm(form, button) {
+ button = button || findElement(form, "input[type=submit]")
if (button) {
const { disabled } = button
button.disabled = false
@@ -73,3 +74,10 @@ function disable(input) {
function enable(input) {
input.disabled = false
}
+
+function findActiveSubmitButton(form) {
+ const element = document.activeElement
+ if (element && element.type == "submit" && element.form == form) {
+ return element
+ }
+}Want to give that a try? |
Of course :-) This was one of the first things I tried. Problem is,
Edit: Again, unfortunately this is not as straight forward as it could be. Should I make the "annotating the clicked submit button and adding click event listeners" version compatible with Turbolinks enabled+disabled? |
Bummer! Here's more-or-less what I was thinking for handling --- a/activestorage/app/javascript/activestorage/ujs.js
+++ b/activestorage/app/javascript/activestorage/ujs.js
@@ -2,16 +2,25 @@ import { DirectUploadsController } from "./direct_uploads_controller"
import { findElement } from "./helpers"
const processingAttribute = "data-direct-uploads-processing"
+const submitButtonsByForm = new WeakMap
let started = false
export function start() {
if (!started) {
started = true
+ document.addEventListener("click", didClick, true)
document.addEventListener("submit", didSubmitForm)
document.addEventListener("ajax:before", didSubmitRemoteElement)
}
}
+function didClick(event) {
+ const { target } = event
+ if (target.tagName == "INPUT" && target.type == "submit" && target.form) {
+ submitButtonsByForm.set(target.form, target)
+ }
+}
+
function didSubmitForm(event) {
handleFormSubmissionEvent(event)
}
@@ -49,7 +58,7 @@ function handleFormSubmissionEvent(event) {
}
function submitForm(form) {
- let button = findElement(form, "input[type=submit]")
+ let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit]")
if (button) {
const { disabled } = button
button.disabled = false
@@ -64,6 +73,7 @@ function submitForm(form) {
button.click()
form.removeChild(button)
}
+ submitButtonsByForm.delete(form)
} |
|
Also good utilization of |
|
Works as expected. Thanks for taking the time showing me some new JS stuff ✌️ Should I base this off 5-2-stable and rename the branch? |
No, PRs should always be opened against master. I'll backport to 5-2 after merging. Mind squashing your commits? |
6272904 to
6278103
Compare
|
Done |
6278103 to
880f977
Compare
|
Thank you! I'll backport this to 5-2-stable as soon as I get baf3d98#commitcomment-30164614 sorted out. |
…multiple-submit-buttons Support multiple submit buttons in Active Storage forms
|
Backported to 5-2-stable: 388a1f3 |
rails/activestorage$ yarn buildproduces a diff: diff --git a/activestorage/app/assets/javascripts/activestorage.js b/activestorage/app/assets/javascripts/activestorage.js
index 8a51805960..375eb6b533 100644
--- a/activestorage/app/assets/javascripts/activestorage.js
+++ b/activestorage/app/assets/javascripts/activestorage.js
@@ -855,7 +855,7 @@
return DirectUploadsController;
}();
var processingAttribute = "data-direct-uploads-processing";
- var submitButtonsByForm = new WeakMap;
+ var submitButtonsByForm = new WeakMap();
var started = false;
function start() {
if (!started) {
@@ -866,8 +866,9 @@
}
}
function didClick(event) {
- if (event.target.tagName == "INPUT" && event.target.type == "submit" && event.target.form) {
- submitButtonsByForm.set(event.target.form, event.target);
+ var target = event.target;
+ if (target.tagName == "INPUT" && target.type == "submit" && target.form) {
+ submitButtonsByForm.set(target.form, target);
}
}
function didSubmitForm(event) {
@@ -902,7 +903,6 @@
}
function submitForm(form) {
var button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit]");
-
if (button) {
var _button = button, disabled = _button.disabled;
button.disabled = false;
Not sure whether it is problem in my local environment. If no, I think we should apply this diff to |
|
Good catch, @bogdanvlviv. I see the same so your local environment is correct. Please do commit that change. I'm guessing that @cseelus updated |
Context rails#33413 (comment) Related to rails#33656
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
When a [`SubmitEvent` is fired][mdn-submit-event], it encodes the
element responsible for the submission. This element can be an `<input
type="submit">`, a `<button type="submit">` element, or the `<form>`
element itself (in the case of submissions initiated by
`HTMLFormElement.requestSubmit()` that omit the `submitter` argument).
According to the [MDN documentation for the `event.submitter`
property][mdn-submitter]:
> An element, indicating the element that sent the submit event to the
> form. While this is often an `<input>` element whose type or a
> `<button>` whose type is `submit`, it could be some other element which
> has initiated a submission process.
> If the submission was not triggered by a button of some kind, the
> value of `submitter` is `null`.
To support submissions from elements other than the `<form>` that can
declare their own [`formmethod`][mdn-formmethod] and
[`formaction`][mdn-formaction], extend the `FormSubmission` object to
encode a reference to the submitter, and add an `HTMLElement` argument
to the `FormSubmitObserver` and `FormSubmissionDelegate` methods.
Invokes [HTMLFormElement.method][mdn-method] instead of
`getAttribute("method")` to defer gracefully handling missing value
fallbacks to the [HTMLFormElement.method][mdn-method] implementation.
[mdn-request-submit]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#Parameters
[mdn-submit-event]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
[mdn-submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
[mdn-formmethod]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formmethod
[mdn-formaction]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-formaction
[mdn-method]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/method
Include Submitter in FormData
===
While constructing the `FormData` during a submission, attempt to read
the submitting `<button>` element's [`[name]`][button-name] and
[`[value]`][button-value] attributes, and encode them as part of the
submission.
While an [`<input type="submit">` element][input-submit] can have a
`[name]` and `[value]` attribute, the `value` is rendered as the
"button"'s text content.
[form-data]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
[button-name]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
[button-value]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-value
[input-submit]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit
Form Submitter polyfill
===
Extend the `FormSubmitObserver` event listening to track `<button
type="submit">` and `<input type="submit">` clicks [in Browsers that
have spotty support][support].
The implementation is largely ported from both [basecamp/turbolinks#4][]
and [rails/rails#33413][].
The `FormSubmitter` type definition is deliberately scoped to the
`FormSubmitObserver` module, since the [Browser-native
`SubmitEvent.submitter` is only as specific as
`HTMLElement`][SubmitEvent], so it's least disruptive to scope
limitations to the polyfilling logic.
[support]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter#Browser_compatibility
[basecamp/turbolinks#4]: https://github.com/basecamp/turbolinks/pull/4
[rails/rails#33413]: rails/rails#33413
[SubmitEvent]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent#Properties
Often times forms have more than one submit button enabling different actions, there are various ways to use this with Rails.
Currently
activestorage.jstakes a somewhat naive approach in just using the firstinput[type=submit]inside a form toclick()and submit the form after direct uploads.This PR utilizes the name and value from
form._ujsDatato use the input the User has really clicked, when submitting the form after an upload.I'm not too happy with the code myself, so this is more of a question if Rails should even support multiple submit buttons per form or not. If so, it might be possible for me to find a cleaner approach.
Edit: When this fix is finshed, it might be better if I backport it to 5-2-stable before.