react-bootstrap
Version:
Bootstrap 3 components build with React
84 lines (69 loc) • 1.71 kB
JavaScript
import React from 'react';
import domUtils from './utils/domUtils';
import EventListener from './utils/EventListener';
/**
* Checks whether a node is within
* a root nodes tree
*
* @param {DOMElement} node
* @param {DOMElement} root
* @returns {boolean}
*/
function isNodeInRoot(node, root) {
while (node) {
if (node === root) {
return true;
}
node = node.parentNode;
}
return false;
}
const DropdownStateMixin = {
getInitialState() {
return {
open: false
};
},
setDropdownState(newState, onStateChangeComplete) {
if (newState) {
this.bindRootCloseHandlers();
} else {
this.unbindRootCloseHandlers();
}
this.setState({
open: newState
}, onStateChangeComplete);
},
handleDocumentKeyUp(e) {
if (e.keyCode === 27) {
this.setDropdownState(false);
}
},
handleDocumentClick(e) {
// If the click originated from within this component
// don't do anything.
if (isNodeInRoot(e.target, React.findDOMNode(this))) {
return;
}
this.setDropdownState(false);
},
bindRootCloseHandlers() {
let doc = domUtils.ownerDocument(this);
this._onDocumentClickListener =
EventListener.listen(doc, 'click', this.handleDocumentClick);
this._onDocumentKeyupListener =
EventListener.listen(doc, 'keyup', this.handleDocumentKeyUp);
},
unbindRootCloseHandlers() {
if (this._onDocumentClickListener) {
this._onDocumentClickListener.remove();
}
if (this._onDocumentKeyupListener) {
this._onDocumentKeyupListener.remove();
}
},
componentWillUnmount() {
this.unbindRootCloseHandlers();
}
};
export default DropdownStateMixin;