Skip to content
Snippets Groups Projects
Commit cf5d5666 authored by Eric Fischer's avatar Eric Fischer
Browse files

Merge pull request #9794 from edx/efischer/prevent_doubleclick

TNL 3294 - Prevent double click creating multiple teams
parents 56dae323 02b72abc
No related merge requests found
......@@ -7,8 +7,8 @@
"common/js/components/views/feedback_prompt"],
function ($, _, gettext, NotificationView, PromptView) {
var toggleExpandCollapse, showLoadingIndicator, hideLoadingIndicator, confirmThenRunOperation,
runOperationShowingMessage, disableElementWhileRunning, getScrollOffset, setScrollOffset,
setScrollTop, redirect, reload, hasChangedAttributes, deleteNotificationHandler,
runOperationShowingMessage, withDisabledElement, disableElementWhileRunning,
getScrollOffset, setScrollOffset, setScrollTop, redirect, reload, hasChangedAttributes, deleteNotificationHandler,
validateRequiredField, validateURLItemEncoding, validateTotalKeyLength, checkTotalKeyLengthViolations;
// see https://openedx.atlassian.net/browse/TNL-889 for what is it and why it's 65
......@@ -87,6 +87,25 @@
});
};
/**
* Wraps a Backbone event callback to disable the event's target element.
*
* This paradigm is designed to be used in Backbone event maps where
* multiple events firing simultaneously is not desired.
*
* @param functionName the function to execute, as a string.
* The function must return a jQuery promise and be able to take an event
*/
withDisabledElement = function(functionName) {
return function(event) {
var view = this;
disableElementWhileRunning($(event.currentTarget), function() {
//call view.functionName(event), with view as the current this
return view[functionName].apply(view, [event]);
});
};
};
/**
* Disables a given element when a given operation is running.
* @param {jQuery} element the element to be disabled.
......@@ -235,6 +254,7 @@
'hideLoadingIndicator': hideLoadingIndicator,
'confirmThenRunOperation': confirmThenRunOperation,
'runOperationShowingMessage': runOperationShowingMessage,
'withDisabledElement': withDisabledElement,
'disableElementWhileRunning': disableElementWhileRunning,
'deleteNotificationHandler': deleteNotificationHandler,
'setScrollTop': setScrollTop,
......
......@@ -17,6 +17,29 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "common
deferred.resolve();
expect(link).not.toHaveClass("is-disabled");
});
it("uses withDisabledElement wrapper to disable element while running a Backbone event handler", function() {
var link,
eventCallback,
event,
deferred = new $.Deferred(),
promise = deferred.promise(),
MockView = Backbone.View.extend({
testFunction: function() {
return promise;
}
}),
testView = new MockView();
setFixtures("<a href='#' id='link'>ripe apples drop about my head</a>");
link = $("#link");
expect(link).not.toHaveClass("is-disabled");
eventCallback = ViewUtils.withDisabledElement('testFunction');
event = {currentTarget: link};
eventCallback.apply(testView, [event]);
expect(link).toHaveClass("is-disabled");
deferred.resolve();
expect(link).not.toHaveClass("is-disabled");
});
});
describe("progress notification", function() {
......@@ -92,4 +115,4 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "common
});
});
});
}).call(this, define || RequireJS.define);
\ No newline at end of file
}).call(this, define || RequireJS.define);
......@@ -6,16 +6,17 @@
'gettext',
'js/views/fields',
'teams/js/models/team',
'common/js/components/utils/view_utils',
'text!teams/templates/edit-team.underscore'],
function (Backbone, _, gettext, FieldViews, TeamModel, editTeamTemplate) {
function (Backbone, _, gettext, FieldViews, TeamModel, ViewUtils, editTeamTemplate) {
return Backbone.View.extend({
maxTeamNameLength: 255,
maxTeamDescriptionLength: 300,
events: {
'click .action-primary': 'createOrUpdateTeam',
'submit form': 'createOrUpdateTeam',
'click .action-primary': ViewUtils.withDisabledElement('createOrUpdateTeam'),
'submit form': ViewUtils.withDisabledElement('createOrUpdateTeam'),
'click .action-cancel': 'cancelAndGoBack'
},
......@@ -124,10 +125,9 @@
var validationResult = this.validateTeamData(data);
if (validationResult.status === false) {
this.showMessage(validationResult.message, validationResult.srMessage);
return;
return $().promise();
}
this.teamModel.save(data, saveOptions)
return view.teamModel.save(data, saveOptions)
.done(function(result) {
view.teamEvents.trigger('teams:update', {
action: view.action,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment