Skip to content
This repository was archived by the owner on Aug 18, 2025. It is now read-only.

Commit b276e47

Browse files
authored
Fix/ie 11 scroll listener (#646)
1 parent a4f9ac1 commit b276e47

File tree

4 files changed

+76
-18
lines changed

4 files changed

+76
-18
lines changed

src/view/drag-handle/util/bind-events.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
// @flow
22
import type { EventBinding, EventOptions } from './event-types';
33

4+
const getOptions = (
5+
shared?: EventOptions,
6+
fromBinding: ?EventOptions,
7+
): EventOptions => ({
8+
...shared,
9+
...fromBinding,
10+
});
11+
412
export const bindEvents = (
513
el: HTMLElement,
614
bindings: EventBinding[],
715
sharedOptions?: EventOptions,
816
) => {
917
bindings.forEach((binding: EventBinding) => {
10-
const options: Object = {
11-
...sharedOptions,
12-
...binding.options,
13-
};
18+
const options: Object = getOptions(sharedOptions, binding.options);
1419

1520
el.addEventListener(binding.eventName, binding.fn, options);
1621
});
@@ -22,10 +27,7 @@ export const unbindEvents = (
2227
sharedOptions?: EventOptions,
2328
) => {
2429
bindings.forEach((binding: EventBinding) => {
25-
const options: Object = {
26-
...sharedOptions,
27-
...binding.options,
28-
};
30+
const options: Object = getOptions(sharedOptions, binding.options);
2931

3032
el.removeEventListener(binding.eventName, binding.fn, options);
3133
});

src/view/drag-handle/util/focus-retainer.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ type FocusRetainer = {|
1313
// our shared state
1414
let retainingFocusFor: ?DraggableId = null;
1515

16+
// Using capture: true as focus events do not bubble
17+
// Additionally doing this prevents us from intercepting the initial
18+
// focus event as it does not bubble up to this listener
19+
const listenerOptions = { capture: true };
20+
1621
// If we focus on
1722
const clearRetentionOnFocusChange = (() => {
1823
let isBound: boolean = false;
@@ -23,11 +28,9 @@ const clearRetentionOnFocusChange = (() => {
2328
}
2429

2530
isBound = true;
26-
// Using capture: true as focus events do not bubble
27-
// Additionally doing this prevents us from intercepting the initial
28-
// focus event as it does not bubble up to this listener
31+
2932
// eslint-disable-next-line no-use-before-define
30-
window.addEventListener('focus', onWindowFocusChange, { capture: true });
33+
window.addEventListener('focus', onWindowFocusChange, listenerOptions);
3134
};
3235

3336
const unbind = () => {
@@ -37,7 +40,7 @@ const clearRetentionOnFocusChange = (() => {
3740

3841
isBound = false;
3942
// eslint-disable-next-line no-use-before-define
40-
window.removeEventListener('focus', onWindowFocusChange, { capture: true });
43+
window.removeEventListener('focus', onWindowFocusChange, listenerOptions);
4144
};
4245

4346
// focusin will fire after the focus event fires on the element

src/view/droppable-dimension-publisher/droppable-dimension-publisher.jsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @flow
2-
import { Component, type Node } from 'react';
2+
import React, { type Node } from 'react';
33
import PropTypes from 'prop-types';
44
import memoizeOne from 'memoize-one';
55
import invariant from 'tiny-invariant';
@@ -81,7 +81,13 @@ type WatchingScroll = {|
8181
options: ScrollOptions,
8282
|};
8383

84-
export default class DroppableDimensionPublisher extends Component<Props> {
84+
const listenerOptions = {
85+
passive: true,
86+
};
87+
88+
export default class DroppableDimensionPublisher extends React.Component<
89+
Props,
90+
> {
8591
/* eslint-disable react/sort-comp */
8692
watchingScroll: ?WatchingScroll = null;
8793
callbacks: DroppableCallbacks;
@@ -165,9 +171,11 @@ export default class DroppableDimensionPublisher extends Component<Props> {
165171
closestScrollable,
166172
};
167173

168-
closestScrollable.addEventListener('scroll', this.onClosestScroll, {
169-
passive: true,
170-
});
174+
closestScrollable.addEventListener(
175+
'scroll',
176+
this.onClosestScroll,
177+
listenerOptions,
178+
);
171179
};
172180

173181
unwatchScroll = () => {
@@ -184,6 +192,7 @@ export default class DroppableDimensionPublisher extends Component<Props> {
184192
watching.closestScrollable.removeEventListener(
185193
'scroll',
186194
this.onClosestScroll,
195+
listenerOptions,
187196
);
188197
this.watchingScroll = null;
189198
};

test/unit/view/droppable-dimension-publisher.spec.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,50 @@ describe('DraggableDimensionPublisher', () => {
10391039
callbacks.unwatchScroll();
10401040
wrapper.unmount();
10411041
});
1042+
1043+
// if this is not the case then it will break in IE11
1044+
it('should add and remove events with the same event options', () => {
1045+
const marshal: DimensionMarshal = getMarshalStub();
1046+
const wrapper = mount(<ScrollableItem />, withDimensionMarshal(marshal));
1047+
const container: HTMLElement = wrapper.getDOMNode();
1048+
jest.spyOn(container, 'addEventListener');
1049+
jest.spyOn(container, 'removeEventListener');
1050+
1051+
// tell the droppable to watch for scrolling
1052+
const callbacks: DroppableCallbacks =
1053+
marshal.registerDroppable.mock.calls[0][1];
1054+
1055+
// watch scroll will only be called after the dimension is requested
1056+
callbacks.getDimensionAndWatchScroll(preset.windowScroll, scheduled);
1057+
1058+
// assertion
1059+
const expectedOptions = {
1060+
passive: true,
1061+
};
1062+
expect(container.addEventListener).toHaveBeenCalledWith(
1063+
'scroll',
1064+
expect.any(Function),
1065+
expectedOptions,
1066+
);
1067+
expect(container.removeEventListener).not.toHaveBeenCalled();
1068+
container.addEventListener.mockReset();
1069+
1070+
// unwatching scroll
1071+
callbacks.unwatchScroll();
1072+
1073+
// assertion
1074+
expect(container.removeEventListener).toHaveBeenCalledWith(
1075+
'scroll',
1076+
expect.any(Function),
1077+
expectedOptions,
1078+
);
1079+
expect(container.removeEventListener).toHaveBeenCalledTimes(1);
1080+
expect(container.addEventListener).not.toHaveBeenCalled();
1081+
1082+
// cleanup
1083+
container.addEventListener.mockRestore();
1084+
container.removeEventListener.mockRestore();
1085+
});
10421086
});
10431087

10441088
describe('forced scroll', () => {

0 commit comments

Comments
 (0)