From 9ca712348e547815d04a6e1e13b9faf71ebce987 Mon Sep 17 00:00:00 2001 From: Patrick Toomey Date: Thu, 9 Mar 2017 23:06:18 -0700 Subject: Prevent event propogation if element is disabled when event chain begins. The existing UJS event behavior relies on browsers not sending events for various events when an element is disabled. For example, imagine the following: The above button is disabled, so browsers will not trigger a click event and all UJS behavior is prevented. However, imagine a button like this: The above is treated differently by browsers such as Chrome/Safari. These browsers do not consider the strong tag to be disabled, and will trigger click events. UJS has logic to walk up the DOM to find an associated element subject to UJS behavior. But, this logic does not take into account the disabled status of the element. I originally thought we could simply change the selectors used to match elements to ignore disabled elements. However, UJS disables some elements as part of the event chain. So, an element might match early in the chain and then fail to match later. Instead of changing the selectors I added a callback to the chain that calls `stopEverything` if an element is disabled when the event chain begins. --- actionview/app/assets/javascripts/features/disable.coffee | 4 ++++ actionview/app/assets/javascripts/rails-ujs.coffee | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'actionview/app') diff --git a/actionview/app/assets/javascripts/features/disable.coffee b/actionview/app/assets/javascripts/features/disable.coffee index e8cce7da40..90aa3bdf0e 100644 --- a/actionview/app/assets/javascripts/features/disable.coffee +++ b/actionview/app/assets/javascripts/features/disable.coffee @@ -2,6 +2,10 @@ { matches, getData, setData, stopEverything, formElements } = Rails +Rails.handleDisabledElement = (e) -> + element = this + stopEverything(e) if element.disabled + # Unified function to enable an element (link, button and form) Rails.enableElement = (e) -> element = if e instanceof Event then e.target else e diff --git a/actionview/app/assets/javascripts/rails-ujs.coffee b/actionview/app/assets/javascripts/rails-ujs.coffee index df889ce067..afe7d6f7a3 100644 --- a/actionview/app/assets/javascripts/rails-ujs.coffee +++ b/actionview/app/assets/javascripts/rails-ujs.coffee @@ -12,7 +12,7 @@ fire, delegate getData, $ refreshCSRFTokens, CSRFProtection - enableElement, disableElement + enableElement, disableElement, handleDisabledElement handleConfirm handleRemote, formSubmitButtonClick, handleMetaClick handleMethod @@ -44,19 +44,23 @@ Rails.start = -> delegate document, Rails.buttonDisableSelector, 'ajax:complete', enableElement delegate document, Rails.buttonDisableSelector, 'ajax:stopped', enableElement + delegate document, Rails.linkClickSelector, 'click', handleDisabledElement delegate document, Rails.linkClickSelector, 'click', handleConfirm delegate document, Rails.linkClickSelector, 'click', handleMetaClick delegate document, Rails.linkClickSelector, 'click', disableElement delegate document, Rails.linkClickSelector, 'click', handleRemote delegate document, Rails.linkClickSelector, 'click', handleMethod + delegate document, Rails.buttonClickSelector, 'click', handleDisabledElement delegate document, Rails.buttonClickSelector, 'click', handleConfirm delegate document, Rails.buttonClickSelector, 'click', disableElement delegate document, Rails.buttonClickSelector, 'click', handleRemote + delegate document, Rails.inputChangeSelector, 'change', handleDisabledElement delegate document, Rails.inputChangeSelector, 'change', handleConfirm delegate document, Rails.inputChangeSelector, 'change', handleRemote + delegate document, Rails.formSubmitSelector, 'submit', handleDisabledElement delegate document, Rails.formSubmitSelector, 'submit', handleConfirm delegate document, Rails.formSubmitSelector, 'submit', handleRemote # Normal mode submit @@ -65,6 +69,7 @@ Rails.start = -> delegate document, Rails.formSubmitSelector, 'ajax:send', disableElement delegate document, Rails.formSubmitSelector, 'ajax:complete', enableElement + delegate document, Rails.formInputClickSelector, 'click', handleDisabledElement delegate document, Rails.formInputClickSelector, 'click', handleConfirm delegate document, Rails.formInputClickSelector, 'click', formSubmitButtonClick -- cgit v1.2.3