From 66f0f921ddcbc943f72b97187df28a76fb4b738d Mon Sep 17 00:00:00 2001 From: jquense Date: Wed, 10 Jun 2015 14:18:55 -0400 Subject: [PATCH] [added] enforceFocus prop to Modal Allows you to configure whether the modal should enforce focus when open. Ideally this doesn't need to be a public API, but in the case of static models (like in the docs) you need to turn it off, because you can't assume its the only one open on the page. --- docs/examples/ModalStatic.js | 1 + package.json | 2 +- src/Modal.js | 59 +++++++++++++++++++++++++++++++++--- src/utils/domUtils.js | 15 +++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/docs/examples/ModalStatic.js b/docs/examples/ModalStatic.js index 545efbee73..f01a4d058e 100644 --- a/docs/examples/ModalStatic.js +++ b/docs/examples/ModalStatic.js @@ -1,6 +1,7 @@ const modalInstance = (
document.detachEvent('onfocusin', handler); + } else { + document.addEventListener('focus', handler, true); + remove = () => document.removeEventListener('focus', handler, true); + } + return { remove }; +} + +let scrollbarSize; if ( domUtils.canUseDom) { let scrollDiv = document.createElement('div'); @@ -60,7 +82,8 @@ const Modal = React.createClass({ closeButton: React.PropTypes.bool, animation: React.PropTypes.bool, onRequestHide: React.PropTypes.func.isRequired, - dialogClassName: React.PropTypes.string + dialogClassName: React.PropTypes.string, + enforceFocus: React.PropTypes.bool }, getDefaultProps() { @@ -69,10 +92,15 @@ const Modal = React.createClass({ backdrop: true, keyboard: true, animation: true, - closeButton: true + closeButton: true, + enforceFocus: true }; }, + getInitialState(){ + return { }; + }, + render() { let state = this.state; let modalStyle = { ...state.dialogStyles, display: 'block'}; @@ -107,7 +135,7 @@ const Modal = React.createClass({ ); return this.props.backdrop ? - this.renderBackdrop(modal) : modal; + this.renderBackdrop(modal, state.backdropStyles) : modal; }, renderBackdrop(modal) { @@ -132,8 +160,8 @@ const Modal = React.createClass({ let closeButton; if (this.props.closeButton) { closeButton = ( - - ); + + ); } return ( @@ -169,6 +197,10 @@ const Modal = React.createClass({ this._onWindowResizeListener = EventListener.listen(win, 'resize', this.handleWindowResize); + if (this.props.enforceFocus) { + this._onFocusinListener = onFocus(this, this.enforceFocus); + } + let container = getContainer(this); container.className += container.className.length ? ' modal-open' : 'modal-open'; @@ -199,6 +231,10 @@ const Modal = React.createClass({ this._onDocumentKeyupListener.remove(); this._onWindowResizeListener.remove(); + if (this._onFocusinListener) { + this._onFocusinListener.remove(); + } + let container = getContainer(this); container.className = container.className.replace(/ ?modal-open/, ''); @@ -237,6 +273,19 @@ const Modal = React.createClass({ } }, + enforceFocus() { + if ( !this.isMounted() ) { + return; + } + + let active = domUtils.activeElement(this) + , modal = React.findDOMNode(this.refs.modal); + + if (modal !== active && !domUtils.contains(modal, active)){ + modal.focus(); + } + }, + _getStyles() { if ( !domUtils.canUseDom ) { return {}; } diff --git a/src/utils/domUtils.js b/src/utils/domUtils.js index ae56eb210d..31fa7c0340 100644 --- a/src/utils/domUtils.js +++ b/src/utils/domUtils.js @@ -26,6 +26,20 @@ function ownerWindow(componentOrElement) { : doc.parentWindow; } +/** + * get the active element, safe in IE + * @return {HTMLElement} + */ +function getActiveElement(componentOrElement){ + let doc = ownerDocument(componentOrElement); + + try { + return doc.activeElement || doc.body; + } catch (e) { + return doc.body; + } +} + /** * Shortcut to compute element style * @@ -160,5 +174,6 @@ export default { getComputedStyles, getOffset, getPosition, + activeElement: getActiveElement, offsetParent: offsetParentFunc };