Skip to content

Commit bca1f0e

Browse files
committed
Merge pull request facebook#1536 from spicyj/facebookgh-1169
Attach empty onclick listener to each node
2 parents fa6fe54 + e096000 commit bca1f0e

File tree

6 files changed

+67
-67
lines changed

6 files changed

+67
-67
lines changed

src/browser/eventPlugins/DefaultEventPluginOrder.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ var DefaultEventPluginOrder = [
3838
keyOf({SelectEventPlugin: null}),
3939
keyOf({CompositionEventPlugin: null}),
4040
keyOf({BeforeInputEventPlugin: null}),
41-
keyOf({AnalyticsEventPlugin: null}),
42-
keyOf({MobileSafariClickEventPlugin: null})
41+
keyOf({AnalyticsEventPlugin: null})
4342
];
4443

4544
module.exports = DefaultEventPluginOrder;

src/browser/eventPlugins/MobileSafariClickEventPlugin.js

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/browser/eventPlugins/SimpleEventPlugin.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
"use strict";
2020

2121
var EventConstants = require('EventConstants');
22+
var EventListener = require('EventListener');
2223
var EventPluginUtils = require('EventPluginUtils');
2324
var EventPropagators = require('EventPropagators');
25+
var ReactMount = require('ReactMount');
2426
var SyntheticClipboardEvent = require('SyntheticClipboardEvent');
2527
var SyntheticEvent = require('SyntheticEvent');
2628
var SyntheticFocusEvent = require('SyntheticFocusEvent');
@@ -31,6 +33,7 @@ var SyntheticTouchEvent = require('SyntheticTouchEvent');
3133
var SyntheticUIEvent = require('SyntheticUIEvent');
3234
var SyntheticWheelEvent = require('SyntheticWheelEvent');
3335

36+
var emptyFunction = require('emptyFunction');
3437
var invariant = require('invariant');
3538
var keyOf = require('keyOf');
3639

@@ -293,6 +296,9 @@ for (var topLevelType in topLevelEventsToDispatchConfig) {
293296
topLevelEventsToDispatchConfig[topLevelType].dependencies = [topLevelType];
294297
}
295298

299+
var ON_CLICK_KEY = keyOf({onClick: null});
300+
var onClickListeners = {};
301+
296302
var SimpleEventPlugin = {
297303

298304
eventTypes: eventTypes,
@@ -412,6 +418,23 @@ var SimpleEventPlugin = {
412418
);
413419
EventPropagators.accumulateTwoPhaseDispatches(event);
414420
return event;
421+
},
422+
423+
didPutListener: function(id, registrationName, listener) {
424+
// Mobile Safari does not fire properly bubble click events on
425+
// non-interactive elements, which means delegated click listeners do not
426+
// fire. The workaround for this bug involves attaching an empty click
427+
// listener on the target node.
428+
if (registrationName === ON_CLICK_KEY) {
429+
var node = ReactMount.getNode(id);
430+
onClickListeners[id] = EventListener.listen(node, 'click', emptyFunction);
431+
}
432+
},
433+
434+
willDeleteListener: function(id, registrationName) {
435+
if (registrationName === ON_CLICK_KEY) {
436+
onClickListeners[id].remove();
437+
}
415438
}
416439

417440
};

src/browser/ui/ReactDefaultInjection.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
2626
var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
2727
var ExecutionEnvironment = require('ExecutionEnvironment');
2828
var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
29-
var MobileSafariClickEventPlugin = require('MobileSafariClickEventPlugin');
3029
var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
3130
var ReactComponentBrowserEnvironment =
3231
require('ReactComponentBrowserEnvironment');
@@ -71,7 +70,6 @@ function inject() {
7170
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
7271
ChangeEventPlugin: ChangeEventPlugin,
7372
CompositionEventPlugin: CompositionEventPlugin,
74-
MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
7573
SelectEventPlugin: SelectEventPlugin,
7674
BeforeInputEventPlugin: BeforeInputEventPlugin
7775
});

src/browser/ui/__tests__/ReactDOMComponent-test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,26 @@ describe('ReactDOMComponent', function() {
343343
'properties to values, not a string.'
344344
);
345345
});
346+
347+
it("should execute custom event plugin listening behavior", function() {
348+
var React = require('React');
349+
var SimpleEventPlugin = require('SimpleEventPlugin');
350+
351+
SimpleEventPlugin.didPutListener = mocks.getMockFunction();
352+
SimpleEventPlugin.willDeleteListener = mocks.getMockFunction();
353+
354+
var container = document.createElement('div');
355+
React.renderComponent(
356+
<div onClick={() => true} />,
357+
container
358+
);
359+
360+
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
361+
362+
React.unmountComponentAtNode(container);
363+
364+
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
365+
});
346366
});
347367

348368
describe('updateComponent', function() {

src/event/EventPluginHub.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ var EventPluginHub = {
171171
var bankForRegistrationName =
172172
listenerBank[registrationName] || (listenerBank[registrationName] = {});
173173
bankForRegistrationName[id] = listener;
174+
175+
var PluginModule =
176+
EventPluginRegistry.registrationNameModules[registrationName];
177+
if (PluginModule && PluginModule.didPutListener) {
178+
PluginModule.didPutListener(id, registrationName, listener);
179+
}
174180
},
175181

176182
/**
@@ -190,7 +196,14 @@ var EventPluginHub = {
190196
* @param {string} registrationName Name of listener (e.g. `onClick`).
191197
*/
192198
deleteListener: function(id, registrationName) {
199+
var PluginModule =
200+
EventPluginRegistry.registrationNameModules[registrationName];
201+
if (PluginModule && PluginModule.willDeleteListener) {
202+
PluginModule.willDeleteListener(id, registrationName);
203+
}
204+
193205
var bankForRegistrationName = listenerBank[registrationName];
206+
// TODO: This should never be null -- when is it?
194207
if (bankForRegistrationName) {
195208
delete bankForRegistrationName[id];
196209
}
@@ -203,6 +216,16 @@ var EventPluginHub = {
203216
*/
204217
deleteAllListeners: function(id) {
205218
for (var registrationName in listenerBank) {
219+
if (!listenerBank[registrationName][id]) {
220+
continue;
221+
}
222+
223+
var PluginModule =
224+
EventPluginRegistry.registrationNameModules[registrationName];
225+
if (PluginModule && PluginModule.willDeleteListener) {
226+
PluginModule.willDeleteListener(id, registrationName);
227+
}
228+
206229
delete listenerBank[registrationName][id];
207230
}
208231
},

0 commit comments

Comments
 (0)