Skip to content
Snippets Groups Projects
Commit 74741247 authored by Tom Robinson's avatar Tom Robinson
Browse files

Implement onclickout functionality directly in our OnClickOutsideWrapper. Resolves #3023

parent 35d9642a
Branches
Tags
No related merge requests found
import React, { Component, PropTypes } from "react";
import ReactDOM from "react-dom";
import ClickOutComponent from 'react-onclickout';
// this feels a little silly, but we have this component ONLY so that we can add the OnClickOutside functionality on an
// arbitrary set of html content. I wish we could do that more easily
// keep track of the order popovers were opened so we only close the last one when clicked outside
var popoverStack = [];
const popoverStack = [];
const ESC_KEY = 27;
export default class OnClickOutsideWrapper extends ClickOutComponent {
export default class OnClickOutsideWrapper extends Component {
static propTypes = {
handleDismissal: PropTypes.func.isRequired
}
};
static defaultProps = {
dismissOnClickOutside: true,
dismissOnEscape: true
};
constructor() {
super();
this.handleKeyPress = this.handleKeyPress.bind(this);
}
componentDidMount() {
super.componentDidMount();
// necessary to ignore click events that fire immediately, causing modals/popovers to close prematurely
this.timeout = setTimeout(() => {
this._timeout = setTimeout(() => {
popoverStack.push(this);
// HACK: set the z-index of the parent element to ensure it's always on top
// NOTE: this actually doesn't seem to be working correctly for popovers since PopoverBody creates a stacking context
ReactDOM.findDOMNode(this).parentNode.style.zIndex = popoverStack.length + 2; // HACK: add 2 to ensure it's in front of main and nav elements
}, 10);
document.addEventListener('keydown', this.handleKeyPress, false)
}
// HACK: set the z-index of the parent element to ensure it"s always on top
// NOTE: this actually doesn"t seem to be working correctly for popovers since PopoverBody creates a stacking context
ReactDOM.findDOMNode(this).parentNode.style.zIndex = popoverStack.length + 2; // HACK: add 2 to ensure it"s in front of main and nav elements
handleKeyPress (event) {
if (event.keyCode === ESC_KEY) {
event.preventDefault();
this.onClickOut();
}
if (this.props.dismissOnEscape) {
document.addEventListener("keydown", this._handleKeyPress, false);
}
if (this.props.dismissOnClickOutside) {
window.addEventListener("click", this._handleClick, false);
}
}, 0);
}
componentWillUnmount() {
super.componentWillUnmount();
document.removeEventListener('keydown', this.handleKeyPress, false);
document.removeEventListener("keydown", this._handleKeyPress, false);
window.removeEventListener("click", this._handleClick, false);
clearTimeout(this._timeout);
// remove popover from the stack
var index = popoverStack.indexOf(this);
if (index >= 0) {
popoverStack.splice(index, 1);
}
clearTimeout(this.timeout);
}
onClickOut(e) {
_handleClick = (e) => {
if (!ReactDOM.findDOMNode(this).contains(e.target)) {
this._handleDismissal();
}
}
_handleKeyPress = (event) => {
if (event.keyCode === ESC_KEY) {
event.preventDefault();
this._handleDismissal();
}
}
_handleDismissal(e) {
// only propagate event for the popover on top of the stack
if (this === popoverStack[popoverStack.length - 1]) {
this.props.handleDismissal(e);
......@@ -59,6 +67,6 @@ export default class OnClickOutsideWrapper extends ClickOutComponent {
}
render() {
return this.props.children;
return React.Children.only(this.props.children);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment