File tree Expand file tree Collapse file tree 10 files changed +189
-1
lines changed
Expand file tree Collapse file tree 10 files changed +189
-1
lines changed Original file line number Diff line number Diff line change 88 "dependencies" : {
99 "classnames" : " ^2.2.5" ,
1010 "core-js" : " ^2.4.1" ,
11+ "draft-js" : " ^0.10.5" ,
1112 "prop-types" : " ^15.6.0" ,
1213 "query-string" : " ^4.2.3" ,
1314 "react" : " ^15.4.1" ,
Original file line number Diff line number Diff line change 1616 < title > React App</ title >
1717 < script src ="
https://unpkg.com/[email protected] /prop-types.js "
> </ script > 1818 < script src ="
https://unpkg.com/[email protected] /umd/expect.min.js "
> </ script > 19+ < script src ="
https://unpkg.com/[email protected] /dist/immutable.js "
> </ script > 1920 </ head >
2021 < body >
2122 < div id ="root "> </ div >
Original file line number Diff line number Diff line change @@ -64,6 +64,7 @@ class Header extends React.Component {
6464 < option value = "/event-pooling" > Event Pooling</ option >
6565 < option value = "/custom-elements" > Custom Elements</ option >
6666 < option value = "/media-events" > Media Events</ option >
67+ < option value = "/selection-events" > Selection Events</ option >
6768 </ select >
6869 </ label >
6970 < label htmlFor = "react_version" >
Original file line number Diff line number Diff line change 1+ const React = window . React ;
2+ const ReactDOM = window . ReactDOM ;
3+
4+ class IframePortal extends React . Component {
5+ state = { ref : null } ;
6+
7+ handleRef = ( ref ) => {
8+ if ( ref !== this . state . ref ) {
9+ this . setState ( { ref} ) ;
10+ if ( ref && ref . contentDocument && this . props . head ) {
11+ ref . contentDocument . head . innerHTML = this . props . head ;
12+ }
13+ }
14+ } ;
15+
16+ render ( ) {
17+ const { ref} = this . state ;
18+ let portal = null ;
19+ if ( ref && ref . contentDocument ) {
20+ portal = ReactDOM . createPortal (
21+ this . props . children ,
22+ ref . contentDocument . body ,
23+ ) ;
24+ }
25+
26+ return (
27+ < div >
28+ < iframe
29+ style = { { border : 'none' , height : this . props . height } }
30+ ref = { this . handleRef } />
31+ { portal }
32+ </ div >
33+ ) ;
34+ }
35+ }
36+
37+ class IframeSubtree extends React . Component {
38+ warned = false ;
39+ render ( ) {
40+ if ( ! this . warned ) {
41+ console . error ( `IFrame has not yet been implemented for React v${ React . version } ` ) ;
42+ this . warned = true ;
43+ }
44+ return (
45+ < div >
46+ { this . props . children }
47+ </ div >
48+ )
49+ }
50+ }
51+
52+
53+ export default ReactDOM . createPortal ? IframePortal : IframeSubtree ;
Original file line number Diff line number Diff line change @@ -11,6 +11,7 @@ import ErrorHandling from './error-handling';
1111import EventPooling from './event-pooling' ;
1212import CustomElementFixtures from './custom-elements' ;
1313import MediaEventsFixtures from './media-events' ;
14+ import SelectionEventsFixtures from './selection-events' ;
1415
1516const React = window . React ;
1617
@@ -46,6 +47,8 @@ function FixturesPage() {
4647 return < CustomElementFixtures /> ;
4748 case '/media-events' :
4849 return < MediaEventsFixtures /> ;
50+ case '/selection-events' :
51+ return < SelectionEventsFixtures /> ;
4952 default :
5053 return < p > Please select a test fixture.</ p > ;
5154 }
Original file line number Diff line number Diff line change 1+ import TestCase from '../../TestCase' ;
2+ import Iframe from '../../Iframe' ;
3+ const React = window . React ;
4+ const { EditorState, Editor} = window . Draft ;
5+
6+
7+ export default class DraftJsEditorTestCase extends React . Component {
8+ constructor ( props ) {
9+ super ( props ) ;
10+ this . state = { editorState : EditorState . createEmpty ( ) } ;
11+ this . onChange = ( editorState ) => this . setState ( { editorState} ) ;
12+ }
13+ render ( ) {
14+ return (
15+ < TestCase
16+ title = "Cursor Position in a Draft.js Editor"
17+ description = "Draft.js is a rich text editor system for React.
18+ This verifies that the selection restoration functionality it depends on
19+ works in an iframe." >
20+ < TestCase . Steps >
21+ < li > Enter some text into the Draft.js editor (grey outlined box)</ li >
22+ < li > Change your cursor position to somewhere in the middle of the text</ li >
23+ < li > Enter a new character</ li >
24+ </ TestCase . Steps >
25+ < TestCase . ExpectedResult >
26+ The cursor should not jump positions
27+ </ TestCase . ExpectedResult >
28+ < Iframe height = { 60 } >
29+ < div style = { { border : '1px solid grey' } } >
30+ < Editor editorState = { this . state . editorState } onChange = { this . onChange } />
31+ </ div >
32+ </ Iframe >
33+ </ TestCase >
34+ ) ;
35+ }
36+ }
Original file line number Diff line number Diff line change 1+ import TestCase from '../../TestCase' ;
2+ import Iframe from '../../Iframe' ;
3+ const React = window . React ;
4+
5+ export default class ReorderedInputsTestCase extends React . Component {
6+
7+ state = { count : 0 } ;
8+
9+ componentDidMount ( ) {
10+ this . interval = setInterval ( ( ) => {
11+ this . setState ( { count : this . state . count + 1 } ) ;
12+ } , 2000 ) ;
13+ }
14+
15+ componentWillUnmount ( ) {
16+ clearInterval ( this . interval ) ;
17+ }
18+
19+ renderInputs ( ) {
20+ const inputs = [
21+ < input key = { 1 } defaultValue = "Foo" /> ,
22+ < input key = { 2 } defaultValue = "Bar" /> ,
23+ ] ;
24+ if ( this . state . count % 2 === 0 ) {
25+ inputs . reverse ( ) ;
26+ }
27+ return inputs ;
28+ }
29+
30+ render ( ) {
31+ return (
32+ < TestCase
33+ title = "Reordered input elements in iframes"
34+ description = "" >
35+ < TestCase . Steps >
36+ < li > The two inputs below swap positions every two seconds</ li >
37+ < li > Select the text in either of them</ li >
38+ < li > Wait for the swap to occur</ li >
39+ </ TestCase . Steps >
40+ < TestCase . ExpectedResult >
41+ The selection you made should be maintained
42+ </ TestCase . ExpectedResult >
43+ < Iframe height = { 50 } >
44+ { this . renderInputs ( ) }
45+ </ Iframe >
46+ </ TestCase >
47+ )
48+ }
49+ }
Original file line number Diff line number Diff line change 1+ import FixtureSet from '../../FixtureSet' ;
2+ import TestCase from '../../TestCase' ;
3+ import Iframe from '../../Iframe' ;
4+ import ReorderedInputsTestCase from './ReorderedInputsTestCase' ;
5+ import DraftJsEditorTestCase from './DraftJsEditorTestCase' ;
6+ const React = window . React ;
7+
8+
9+ export default function SelectionEvents ( ) {
10+ return (
11+ < FixtureSet
12+ title = "Selection Restoration in iframes"
13+ description = "
14+ When React commits changes it may perform operations which cause existing
15+ selection state to be lost. This is manually managed by reading the
16+ selection state before commits and then restoring it afterwards.
17+ This selection restoration process should work for elements rendered in
18+ iframes.
19+ " >
20+ < ReorderedInputsTestCase />
21+ < DraftJsEditorTestCase />
22+ </ FixtureSet >
23+ ) ;
24+ } ;
Original file line number Diff line number Diff line change @@ -35,6 +35,11 @@ function loadScript(src) {
3535}
3636
3737export default function loadReact ( ) {
38+ // const DRAFT_JS_PATH = 'https://unpkg.com/[email protected] /dist/Draft.js'; 39+ // @TODO We're using a build of draft-js provided by @acusti in https://github.com/facebook/react/pull/12037
40+ // This is because currently draft doesn't support iframes. This should be changed back to the official
41+ // release on unpkg once the draft fixes are merged.
42+ const DRAFT_JS_PATH = 'https://cdn.rawgit.com/brandcast/draft-js-built/d6c2ffc64914b001411356c0bfab24e831bc5429/dist/Draft.js' ;
3843 let REACT_PATH = 'react.development.js' ;
3944 let DOM_PATH = 'react-dom.development.js' ;
4045
@@ -70,6 +75,9 @@ export default function loadReact() {
7075 window . ReactDOM = window . React ;
7176 } ) ;
7277 }
78+ request = request . then ( ( ) => loadScript ( DRAFT_JS_PATH ) ) ;
79+ // We need Draft.js for the selection events fixture. It has to load
80+ // after ReactDOM.
7381
7482 return request ;
7583}
Original file line number Diff line number Diff line change 21532153 version "4.0.0"
21542154 resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"
21552155
2156+ draft-js@^0.10.5 :
2157+ version "0.10.5"
2158+ resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.5.tgz#bfa9beb018fe0533dbb08d6675c371a6b08fa742"
2159+ dependencies :
2160+ fbjs "^0.8.15"
2161+ immutable "~3.7.4"
2162+ object-assign "^4.1.0"
2163+
21562164duplexer2@^0.1.4 :
21572165 version "0.1.4"
21582166 resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -2672,7 +2680,7 @@ fbjs@^0.8.1, fbjs@^0.8.4:
26722680 setimmediate "^1.0.5"
26732681 ua-parser-js "^0.7.9"
26742682
2675- fbjs@^0.8.16 :
2683+ fbjs@^0.8.15, fbjs@^0.8. 16 :
26762684 version "0.8.16"
26772685 resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
26782686 dependencies :
@@ -3302,6 +3310,10 @@ ignore@^3.3.3:
33023310 version "3.3.3"
33033311 resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
33043312
3313+ immutable@~3.7.4 :
3314+ version "3.7.6"
3315+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
3316+
33053317imurmurhash@^0.1.4 :
33063318 version "0.1.4"
33073319 resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
You can’t perform that action at this time.
0 commit comments