Skip to content

Commit

Permalink
Important bugfix: prevent events from bubbling up to leaflet
Browse files Browse the repository at this point in the history
There are interaction issues around combining React and "native"
javascript components.  We want to prevent events (eg double-click) on
the sidebar from interacting with the underlying leaflet map.
However, we can't just add onDoubleClick to our react markup, because
React synthesises events by installing a single global event handler
at the document, by which time they have already been caught by
leaflet.  So, we need to attach native javascript handlers for
everything we want to stop bubbling up.
  • Loading branch information
markhepburn committed Sep 1, 2017
1 parent 9089979 commit a9156e8
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion src/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ class Tab extends React.Component {
}
}

// We need to prevent *native* events bubbling up to leaflet. React
// attaches a global event handler to the document, so using
// stopPropagation on a React synthetic event has no effect because it
// has already been caught by leaflet. Note the ref on our root
// element.
// We don't ignore 'click', because then our onOpen/Close handlers wouldn't work!
const ignoreEvents = ['dblclick',
'mouseover', 'mouseout', 'mousedown', 'mouseup', 'mousemove', 'wheel',
'pointerdown', 'pointermove', 'pointerup',
'MSPointerDown', 'MSPointerMove', 'MSPointerUp',
'touchdown', 'touchmove', 'touchup',
'dragstart', 'drag', 'dragend'];

// https://github.com/facebook/react/issues/2979#issuecomment-222379916
const TabType = PropTypes.shape({
type: PropTypes.oneOf([Tab])
Expand All @@ -53,6 +66,11 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
]).isRequired,
}

constructor(props) {
super(props);
this.ignoreEvent = this.ignoreEvent.bind(this);
}

onClose(e) {
e.preventDefault();
e.stopPropagation();
Expand All @@ -65,6 +83,19 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
this.props.onOpen && this.props.onOpen(tabid);
}

ignoreEvent(e) {
e.stopPropagation();
e.preventDefault();
}

componentDidMount() {
ignoreEvents.forEach(e => this.rootElement.addEventListener(e, this.ignoreEvent));
}

componentWillUnmount() {
ignoreEvents.forEach(e => this.rootElement.removeEventListener(e, this.ignoreEvent));
}

renderTab(tab) {
var icon;
if (typeof(tab.props.icon) === 'function')
Expand Down Expand Up @@ -99,7 +130,8 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
const bottomtabs = tabs.filter(t => t.props.anchor === 'bottom');
const toptabs = tabs.filter(t => t.props.anchor !== 'bottom');
return (
<div id="sidebar" className={"sidebar leaflet-touch" + position + collapsed}>
<div id={this.props.id} className={"sidebar leaflet-touch" + position + collapsed}
ref={el => this.rootElement = el}>
<div className="sidebar-tabs">
<ul role="tablist"> {/* Top-aligned */}
{toptabs.map(t => this.renderTab(t))}
Expand Down

0 comments on commit a9156e8

Please sign in to comment.