form-single-submit.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. (function ($) {
  2. /**
  3. * Prevents consecutive form submissions of identical form values.
  4. *
  5. * Repetitive form submissions that would submit the identical form values are
  6. * prevented, unless the form values are different from the previously
  7. * submitted values.
  8. *
  9. * This is a simplified re-implementation of a user-agent behavior that should
  10. * be natively supported by major web browsers, but at this time, only Firefox
  11. * has a built-in protection.
  12. *
  13. * A form value-based approach ensures that the constraint is triggered for
  14. * consecutive, identical form submissions only. Compared to that, a form
  15. * button-based approach would (1) rely on [visible] buttons to exist where
  16. * technically not required and (2) require more complex state management if
  17. * there are multiple buttons in a form.
  18. *
  19. * This implementation is based on form-level submit events only and relies on
  20. * jQuery's serialize() method to determine submitted form values. As such, the
  21. * following limitations exist:
  22. *
  23. * - Event handlers on form buttons that preventDefault() do not receive a
  24. * double-submit protection. That is deemed to be fine, since such button
  25. * events typically trigger reversible client-side or server-side operations
  26. * that are local to the context of a form only.
  27. * - Changed values in advanced form controls, such as file inputs, are not part
  28. * of the form values being compared between consecutive form submits (due to
  29. * limitations of jQuery.serialize()). That is deemed to be acceptable,
  30. * because if the user forgot to attach a file, then the size of HTTP payload
  31. * will most likely be small enough to be fully passed to the server endpoint
  32. * within (milli)seconds. If a user mistakenly attached a wrong file and is
  33. * technically versed enough to cancel the form submission (and HTTP payload)
  34. * in order to attach a different file, then that edge-case is not supported
  35. * here.
  36. *
  37. * Lastly, all forms submitted via HTTP GET are idempotent by definition of HTTP
  38. * standards, so excluded in this implementation.
  39. */
  40. Drupal.behaviors.formSingleSubmit = {
  41. attach: function () {
  42. function onFormSubmit (e) {
  43. var $form = $(e.currentTarget);
  44. var formValues = $form.serialize();
  45. var previousValues = $form.attr('data-drupal-form-submit-last');
  46. if (previousValues === formValues) {
  47. e.preventDefault();
  48. }
  49. else {
  50. $form.attr('data-drupal-form-submit-last', formValues);
  51. }
  52. }
  53. $('body').once('form-single-submit')
  54. .delegate('form:not([method~="GET"])', 'submit.singleSubmit', onFormSubmit);
  55. }
  56. };
  57. })(jQuery);