@@ -31,6 +31,28 @@ function getContainer(context){
3131 domUtils . ownerDocument ( context ) . body ;
3232}
3333
34+ /**
35+ * Firefox doesn't have a focusin event so using capture is easiest way to get bubbling
36+ * IE8 can't do addEventListener, but does have onfocus in, so we use that in ie8
37+ * @param {ReactElement|HTMLElement } context
38+ * @param {Function } handler
39+ */
40+ function onFocus ( context , handler ) {
41+ let doc = domUtils . ownerDocument ( context ) ;
42+ let useFocusin = ! doc . addEventListener
43+ , remove ;
44+
45+ if ( useFocusin ) {
46+ document . attachEvent ( 'onfocusin' , handler ) ;
47+ remove = ( ) => document . detachEvent ( 'onfocusin' , handler ) ;
48+ } else {
49+ document . addEventListener ( 'focus' , handler , true ) ;
50+ remove = ( ) => document . removeEventListener ( 'focus' , handler , true ) ;
51+ }
52+ return { remove } ;
53+ }
54+
55+ let scrollbarSize ;
3456
3557if ( domUtils . canUseDom ) {
3658 let scrollDiv = document . createElement ( 'div' ) ;
@@ -60,7 +82,8 @@ const Modal = React.createClass({
6082 closeButton : React . PropTypes . bool ,
6183 animation : React . PropTypes . bool ,
6284 onRequestHide : React . PropTypes . func . isRequired ,
63- dialogClassName : React . PropTypes . string
85+ dialogClassName : React . PropTypes . string ,
86+ enforceFocus : React . PropTypes . bool
6487 } ,
6588
6689 getDefaultProps ( ) {
@@ -69,10 +92,15 @@ const Modal = React.createClass({
6992 backdrop : true ,
7093 keyboard : true ,
7194 animation : true ,
72- closeButton : true
95+ closeButton : true ,
96+ enforceFocus : true
7397 } ;
7498 } ,
7599
100+ getInitialState ( ) {
101+ return { } ;
102+ } ,
103+
76104 render ( ) {
77105 let state = this . state ;
78106 let modalStyle = { ...state . dialogStyles , display : 'block' } ;
@@ -107,7 +135,7 @@ const Modal = React.createClass({
107135 ) ;
108136
109137 return this . props . backdrop ?
110- this . renderBackdrop ( modal ) : modal ;
138+ this . renderBackdrop ( modal , state . backdropStyles ) : modal ;
111139 } ,
112140
113141 renderBackdrop ( modal ) {
@@ -132,8 +160,8 @@ const Modal = React.createClass({
132160 let closeButton ;
133161 if ( this . props . closeButton ) {
134162 closeButton = (
135- < button type = "button" className = "close" aria-hidden = "true" onClick = { this . props . onRequestHide } > ×</ button >
136- ) ;
163+ < button type = "button" className = "close" aria-hidden = "true" onClick = { this . props . onRequestHide } > ×</ button >
164+ ) ;
137165 }
138166
139167 return (
@@ -169,6 +197,10 @@ const Modal = React.createClass({
169197 this . _onWindowResizeListener =
170198 EventListener . listen ( win , 'resize' , this . handleWindowResize ) ;
171199
200+ if ( this . props . enforceFocus ) {
201+ this . _onFocusinListener = onFocus ( this , this . enforceFocus ) ;
202+ }
203+
172204 let container = getContainer ( this ) ;
173205
174206 container . className += container . className . length ? ' modal-open' : 'modal-open' ;
@@ -199,6 +231,10 @@ const Modal = React.createClass({
199231 this . _onDocumentKeyupListener . remove ( ) ;
200232 this . _onWindowResizeListener . remove ( ) ;
201233
234+ if ( this . _onFocusinListener ) {
235+ this . _onFocusinListener . remove ( ) ;
236+ }
237+
202238 let container = getContainer ( this ) ;
203239
204240 container . className = container . className . replace ( / ? m o d a l - o p e n / , '' ) ;
@@ -237,6 +273,19 @@ const Modal = React.createClass({
237273 }
238274 } ,
239275
276+ enforceFocus ( ) {
277+ if ( ! this . isMounted ( ) ) {
278+ return ;
279+ }
280+
281+ let active = domUtils . activeElement ( this )
282+ , modal = React . findDOMNode ( this . refs . modal ) ;
283+
284+ if ( modal !== active && ! domUtils . contains ( modal , active ) ) {
285+ modal . focus ( ) ;
286+ }
287+ } ,
288+
240289 _getStyles ( ) {
241290 if ( ! domUtils . canUseDom ) { return { } ; }
242291
0 commit comments