diff --git a/ckan/public-bs2/base/javascript/modules/basic-form.js b/ckan/public-bs2/base/javascript/modules/basic-form.js index d1e97a4ce95..a3c57b094a1 100644 --- a/ckan/public-bs2/base/javascript/modules/basic-form.js +++ b/ckan/public-bs2/base/javascript/modules/basic-form.js @@ -2,7 +2,23 @@ this.ckan.module('basic-form', function (jQuery) { return { initialize: function () { var message = this._('There are unsaved modifications to this form'); + + $.proxyAll(this, /_on/); + this.el.incompleteFormWarning(message); + + // Disable the submit button on form submit, to prevent multiple + // consecutive form submissions. + this.el.on('submit', this._onSubmit); + }, + _onSubmit() { + + // The button is not disabled immediately so that its value can be sent + // the first time the form is submitted, because the "save" field is + // used in the backend. + setTimeout(function() { + this.el.find('button[name="save"]').attr('disabled', true); + }.bind(this), 0); } }; }); diff --git a/ckan/public-bs2/base/test/spec/modules/basic-form.spec.js b/ckan/public-bs2/base/test/spec/modules/basic-form.spec.js index 3153c44b7b6..9d0628fc86b 100644 --- a/ckan/public-bs2/base/test/spec/modules/basic-form.spec.js +++ b/ckan/public-bs2/base/test/spec/modules/basic-form.spec.js @@ -5,9 +5,11 @@ describe('ckan.module.BasicFormModule()', function () { beforeEach(function () { sinon.stub(jQuery.fn, 'incompleteFormWarning'); - this.el = document.createElement('button'); + this.el = document.createElement('form'); + this.el.innerHTML = '' this.sandbox = ckan.sandbox(); this.sandbox.body = this.fixture; + this.sandbox.body.append(this.el) this.module = new BasicFormModule(this.el, {}, this.sandbox); }); @@ -21,5 +23,17 @@ describe('ckan.module.BasicFormModule()', function () { this.module.initialize(); assert.called(jQuery.fn.incompleteFormWarning); }); + + it('should disable the submit button on form submit', function(done) { + this.module.initialize(); + this.module._onSubmit(); + + setTimeout(function() { + var buttonAttrDisabled = this.el.querySelector('button').getAttribute('disabled'); + + assert.ok(buttonAttrDisabled === 'disabled') + done(); + }.bind(this), 0); + }); }); }); diff --git a/ckan/public/base/javascript/modules/basic-form.js b/ckan/public/base/javascript/modules/basic-form.js index d1e97a4ce95..a3c57b094a1 100644 --- a/ckan/public/base/javascript/modules/basic-form.js +++ b/ckan/public/base/javascript/modules/basic-form.js @@ -2,7 +2,23 @@ this.ckan.module('basic-form', function (jQuery) { return { initialize: function () { var message = this._('There are unsaved modifications to this form'); + + $.proxyAll(this, /_on/); + this.el.incompleteFormWarning(message); + + // Disable the submit button on form submit, to prevent multiple + // consecutive form submissions. + this.el.on('submit', this._onSubmit); + }, + _onSubmit() { + + // The button is not disabled immediately so that its value can be sent + // the first time the form is submitted, because the "save" field is + // used in the backend. + setTimeout(function() { + this.el.find('button[name="save"]').attr('disabled', true); + }.bind(this), 0); } }; }); diff --git a/ckan/public/base/test/spec/modules/basic-form.spec.js b/ckan/public/base/test/spec/modules/basic-form.spec.js index 3153c44b7b6..9d0628fc86b 100644 --- a/ckan/public/base/test/spec/modules/basic-form.spec.js +++ b/ckan/public/base/test/spec/modules/basic-form.spec.js @@ -5,9 +5,11 @@ describe('ckan.module.BasicFormModule()', function () { beforeEach(function () { sinon.stub(jQuery.fn, 'incompleteFormWarning'); - this.el = document.createElement('button'); + this.el = document.createElement('form'); + this.el.innerHTML = '' this.sandbox = ckan.sandbox(); this.sandbox.body = this.fixture; + this.sandbox.body.append(this.el) this.module = new BasicFormModule(this.el, {}, this.sandbox); }); @@ -21,5 +23,17 @@ describe('ckan.module.BasicFormModule()', function () { this.module.initialize(); assert.called(jQuery.fn.incompleteFormWarning); }); + + it('should disable the submit button on form submit', function(done) { + this.module.initialize(); + this.module._onSubmit(); + + setTimeout(function() { + var buttonAttrDisabled = this.el.querySelector('button').getAttribute('disabled'); + + assert.ok(buttonAttrDisabled === 'disabled') + done(); + }.bind(this), 0); + }); }); });