未验证 提交 a2612622 编写于 作者: W WoH

Prevent unintended mouse keys from firing click events

Firefox fires click events on left-, right-
and scroll-wheel (any non-primary mouse key) clicks while other browsers don't.
上级 5b75408e
* Prevent non-primary mouse keys from triggering Rails UJS click handlers.
Firefox fires click events even if the click was triggered by non-primary mouse keys such as right- or scroll-wheel-clicks.
For example, right-clicking a link such as the one described below (with an underlying ajax request registered on click) should not cause that request to occur.
```
<%= link_to 'Remote', remote_path, class: 'remote', remote: true, data: { type: :json } %>
```
Fixes #34541
*Wolfgang Hobmaier*
* Prevent `ActionView::TextHelper#word_wrap` from unexpectedly stripping white space from the _left_ side of lines.
For example, given input like this:
......
......@@ -82,9 +82,12 @@ Rails.formSubmitButtonClick = (e) ->
setData(form, 'ujs:submit-button-formaction', button.getAttribute('formaction'))
setData(form, 'ujs:submit-button-formmethod', button.getAttribute('formmethod'))
Rails.handleMetaClick = (e) ->
Rails.preventInsignificantClick = (e) ->
link = this
method = (link.getAttribute('data-method') or 'GET').toUpperCase()
data = link.getAttribute('data-params')
metaClick = e.metaKey or e.ctrlKey
e.stopImmediatePropagation() if metaClick and method is 'GET' and not data
insignificantMetaClick = metaClick and method is 'GET' and not data
primaryMouseKey = e.button is 0
e.stopImmediatePropagation() if not primaryMouseKey or insignificantMetaClick
......@@ -3,8 +3,8 @@
getData, $
refreshCSRFTokens, CSRFProtection
enableElement, disableElement, handleDisabledElement
handleConfirm
handleRemote, formSubmitButtonClick, handleMetaClick
handleConfirm, preventInsignificantClick
handleRemote, formSubmitButtonClick,
handleMethod
} = Rails
......@@ -35,13 +35,14 @@ Rails.start = ->
delegate document, Rails.buttonDisableSelector, 'ajax:complete', enableElement
delegate document, Rails.buttonDisableSelector, 'ajax:stopped', enableElement
delegate document, Rails.linkClickSelector, 'click', preventInsignificantClick
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', preventInsignificantClick
delegate document, Rails.buttonClickSelector, 'click', handleDisabledElement
delegate document, Rails.buttonClickSelector, 'click', handleConfirm
delegate document, Rails.buttonClickSelector, 'click', disableElement
......@@ -60,6 +61,7 @@ Rails.start = ->
delegate document, Rails.formSubmitSelector, 'ajax:send', disableElement
delegate document, Rails.formSubmitSelector, 'ajax:complete', enableElement
delegate document, Rails.formInputClickSelector, 'click', preventInsignificantClick
delegate document, Rails.formInputClickSelector, 'click', handleDisabledElement
delegate document, Rails.formInputClickSelector, 'click', handleConfirm
delegate document, Rails.formInputClickSelector, 'click', formSubmitButtonClick
......
......@@ -322,6 +322,25 @@ asyncTest('ctrl-clicking on a link does not disables the link', 6, function() {
start()
})
asyncTest('right/mouse-wheel-clicking on a link does not disables the link', 10, function() {
var link = $('a[data-disable-with]')
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 1 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 1 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 2 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 2 })
App.checkEnabledState(link, 'Click me')
start()
})
asyncTest('button[data-remote][data-disable-with] disables and re-enables', 6, function() {
var button = $('button[data-remote][data-disable-with]')
......
......@@ -250,6 +250,25 @@ asyncTest('ctrl-clicking on a link does not disables the link', 6, function() {
start()
})
asyncTest('right/mouse-wheel-clicking on a link does not disable the link', 10, function() {
var link = $('a[data-disable]')
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 1 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 1 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 2 })
App.checkEnabledState(link, 'Click me')
link.triggerNative('click', { button: 2 })
App.checkEnabledState(link, 'Click me')
start()
})
asyncTest('button[data-remote][data-disable] disables and re-enables', 6, function() {
var button = $('button[data-remote][data-disable]')
......
......@@ -63,6 +63,25 @@ asyncTest('ctrl-clicking on a link does not fire ajaxyness', 0, function() {
setTimeout(function() { start() }, 13)
})
asyncTest('right/mouse-wheel-clicking on a link does not fire ajaxyness', 0, function() {
var link = $('a[data-remote]')
// Ideally, we'd setup an iframe to intercept normal link clicks
// and add a test to make sure the iframe:loaded event is triggered.
// However, jquery doesn't actually cause a native `click` event and
// follow links using `trigger('click')`, it only fires bindings.
link
.removeAttr('data-params')
.bindNative('ajax:beforeSend', function() {
ok(false, 'ajax should not be triggered')
})
link.triggerNative('click', { button: 1 })
link.triggerNative('click', { button: 2 })
setTimeout(function() { start() }, 13)
})
asyncTest('ctrl-clicking on a link still fires ajax for non-GET links and for links with "data-params"', 2, function() {
var link = $('a[data-remote]')
......@@ -148,6 +167,25 @@ asyncTest('clicking on a button with data-remote attribute', 5, function() {
.triggerNative('click')
})
asyncTest('right/mouse-wheel-clicking on a button with data-remote attribute does not fire ajaxyness', 0, function() {
var button = $('button[data-remote]')
// Ideally, we'd setup an iframe to intercept normal link clicks
// and add a test to make sure the iframe:loaded event is triggered.
// However, jquery doesn't actually cause a native `click` event and
// follow links using `trigger('click')`, it only fires bindings.
button
.removeAttr('data-params')
.bindNative('ajax:beforeSend', function() {
ok(false, 'ajax should not be triggered')
})
button.triggerNative('click', { button: 1 })
button.triggerNative('click', { button: 2 })
setTimeout(function() { start() }, 13)
})
asyncTest('changing a select option with data-remote attribute', 5, function() {
buildSelect()
......
......@@ -71,7 +71,7 @@ try {
} catch (e) {
_MouseEvent = function(type, options) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent(type, options.bubbles, options.cancelable, window, options.detail, 0, 0, 80, 20, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, null)
evt.initMouseEvent(type, options.bubbles, options.cancelable, window, options.detail, 0, 0, 80, 20, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, null)
return evt
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册