(function ($) { /** * Prevents consecutive form submissions of identical form values. * * Repetitive form submissions that would submit the identical form values are * prevented, unless the form values are different from the previously * submitted values. * * This is a simplified re-implementation of a user-agent behavior that should * be natively supported by major web browsers, but at this time, only Firefox * has a built-in protection. * * A form value-based approach ensures that the constraint is triggered for * consecutive, identical form submissions only. Compared to that, a form * button-based approach would (1) rely on [visible] buttons to exist where * technically not required and (2) require more complex state management if * there are multiple buttons in a form. * * This implementation is based on form-level submit events only and relies on * jQuery's serialize() method to determine submitted form values. As such, the * following limitations exist: * * - Event handlers on form buttons that preventDefault() do not receive a * double-submit protection. That is deemed to be fine, since such button * events typically trigger reversible client-side or server-side operations * that are local to the context of a form only. * - Changed values in advanced form controls, such as file inputs, are not part * of the form values being compared between consecutive form submits (due to * limitations of jQuery.serialize()). That is deemed to be acceptable, * because if the user forgot to attach a file, then the size of HTTP payload * will most likely be small enough to be fully passed to the server endpoint * within (milli)seconds. If a user mistakenly attached a wrong file and is * technically versed enough to cancel the form submission (and HTTP payload) * in order to attach a different file, then that edge-case is not supported * here. * * Lastly, all forms submitted via HTTP GET are idempotent by definition of HTTP * standards, so excluded in this implementation. */ Drupal.behaviors.formSingleSubmit = { attach: function () { function onFormSubmit (e) { var $form = $(e.currentTarget); var formValues = $form.serialize(); var previousValues = $form.attr('data-drupal-form-submit-last'); if (previousValues === formValues) { e.preventDefault(); } else { $form.attr('data-drupal-form-submit-last', formValues); } } $('body').once('form-single-submit') .delegate('form:not([method~="GET"])', 'submit.singleSubmit', onFormSubmit); } }; })(jQuery);