Skip to content

Commit

Permalink
Implement selection event fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon Dail committed Jan 30, 2018
1 parent 2c3c59e commit dff3e52
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 1 deletion.
1 change: 1 addition & 0 deletions fixtures/dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dependencies": {
"classnames": "^2.2.5",
"core-js": "^2.4.1",
"draft-js": "^0.10.5",
"prop-types": "^15.6.0",
"query-string": "^4.2.3",
"react": "^15.4.1",
Expand Down
1 change: 1 addition & 0 deletions fixtures/dom/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<title>React App</title>
<script src="https://unpkg.com/prop-types@15.5.6/prop-types.js"></script>
<script src="https://unpkg.com/expect@1.20.2/umd/expect.min.js"></script>
<script src="https://unpkg.com/immutable@3.8.2/dist/immutable.js"></script>
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 1 addition & 0 deletions fixtures/dom/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Header extends React.Component {
<option value="/event-pooling">Event Pooling</option>
<option value="/custom-elements">Custom Elements</option>
<option value="/media-events">Media Events</option>
<option value="/selection-events">Selection Events</option>
</select>
</label>
<label htmlFor="react_version">
Expand Down
53 changes: 53 additions & 0 deletions fixtures/dom/src/components/Iframe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const React = window.React;
const ReactDOM = window.ReactDOM;

class IframePortal extends React.Component {
state = {ref: null};

handleRef = (ref) => {
if (ref !== this.state.ref) {
this.setState({ref});
if (ref && ref.contentDocument && this.props.head) {
ref.contentDocument.head.innerHTML = this.props.head;
}
}
};

render() {
const {ref} = this.state;
let portal = null;
if (ref && ref.contentDocument) {
portal = ReactDOM.createPortal(
this.props.children,
ref.contentDocument.body,
);
}

return (
<div>
<iframe
style={{ border: 'none', height: this.props.height }}
ref={this.handleRef} />
{portal}
</div>
);
}
}

class IframeSubtree extends React.Component {
warned = false;
render() {
if (!this.warned) {
console.error(`IFrame has not yet been implemented for React v${React.version}`);
this.warned = true;
}
return (
<div>
{this.props.children}
</div>
)
}
}


export default ReactDOM.createPortal ? IframePortal : IframeSubtree;
3 changes: 3 additions & 0 deletions fixtures/dom/src/components/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ErrorHandling from './error-handling';
import EventPooling from './event-pooling';
import CustomElementFixtures from './custom-elements';
import MediaEventsFixtures from './media-events';
import SelectionEventsFixtures from './selection-events';

const React = window.React;

Expand Down Expand Up @@ -46,6 +47,8 @@ function FixturesPage() {
return <CustomElementFixtures />;
case '/media-events':
return <MediaEventsFixtures />;
case '/selection-events':
return <SelectionEventsFixtures />;
default:
return <p>Please select a test fixture.</p>;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import TestCase from '../../TestCase';
import Iframe from '../../Iframe';
const React = window.React;
const {EditorState, Editor} = window.Draft;


export default class DraftJsEditorTestCase extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<TestCase
title="Cursor Position in a Draft.js Editor"
description="Draft.js is a rich text editor system for React.
This verifies that the selection restoration functionality it depends on
works in an iframe.">
<TestCase.Steps>
<li>Enter some text into the Draft.js editor (grey outlined box)</li>
<li>Change your cursor position to somewhere in the middle of the text</li>
<li>Enter a new character</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
The cursor should not jump positions
</TestCase.ExpectedResult>
<Iframe height={60}>
<div style={{ border: '1px solid grey' }}>
<Editor editorState={this.state.editorState} onChange={this.onChange} />
</div>
</Iframe>
</TestCase>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import TestCase from '../../TestCase';
import Iframe from '../../Iframe';
const React = window.React;

export default class ReorderedInputsTestCase extends React.Component {

state = { count: 0 };

componentDidMount() {
this.interval = setInterval(() => {
this.setState({ count: this.state.count + 1 });
}, 2000);
}

componentWillUnmount() {
clearInterval(this.interval);
}

renderInputs() {
const inputs = [
<input key={1} defaultValue="Foo" />,
<input key={2} defaultValue="Bar" />,
];
if (this.state.count % 2 === 0) {
inputs.reverse();
}
return inputs;
}

render() {
return (
<TestCase
title="Reordered input elements in iframes"
description="">
<TestCase.Steps>
<li>The two inputs below swap positions every two seconds</li>
<li>Select the text in either of them</li>
<li>Wait for the swap to occur</li>
</TestCase.Steps>
<TestCase.ExpectedResult>
The selection you made should be maintained
</TestCase.ExpectedResult>
<Iframe height={50}>
{this.renderInputs()}
</Iframe>
</TestCase>
)
}
}
24 changes: 24 additions & 0 deletions fixtures/dom/src/components/fixtures/selection-events/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import FixtureSet from '../../FixtureSet';
import TestCase from '../../TestCase';
import Iframe from '../../Iframe';
import ReorderedInputsTestCase from './ReorderedInputsTestCase';
import DraftJsEditorTestCase from './DraftJsEditorTestCase';
const React = window.React;


export default function SelectionEvents() {
return (
<FixtureSet
title="Selection Restoration in iframes"
description="
When React commits changes it may perform operations which cause existing
selection state to be lost. This is manually managed by reading the
selection state before commits and then restoring it afterwards.
This selection restoration process should work for elements rendered in
iframes.
">
<ReorderedInputsTestCase />
<DraftJsEditorTestCase />
</FixtureSet>
);
};
8 changes: 8 additions & 0 deletions fixtures/dom/src/react-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ function loadScript(src) {
}

export default function loadReact() {
// const DRAFT_JS_PATH = 'https://unpkg.com/draft-js@0.10.5/dist/Draft.js';
// @TODO We're using a build of draft-js provided by @acusti in https://github.com/facebook/react/pull/12037
// This is because currently draft doesn't support iframes. This should be changed back to the official
// release on unpkg once the draft fixes are merged.
const DRAFT_JS_PATH = 'https://cdn.rawgit.com/brandcast/draft-js-built/d6c2ffc64914b001411356c0bfab24e831bc5429/dist/Draft.js';
let REACT_PATH = 'react.development.js';
let DOM_PATH = 'react-dom.development.js';

Expand Down Expand Up @@ -70,6 +75,9 @@ export default function loadReact() {
window.ReactDOM = window.React;
});
}
request = request.then(() => loadScript(DRAFT_JS_PATH));
// We need Draft.js for the selection events fixture. It has to load
// after ReactDOM.

return request;
}
14 changes: 13 additions & 1 deletion fixtures/dom/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,14 @@ dotenv@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"

draft-js@^0.10.5:
version "0.10.5"
resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.5.tgz#bfa9beb018fe0533dbb08d6675c371a6b08fa742"
dependencies:
fbjs "^0.8.15"
immutable "~3.7.4"
object-assign "^4.1.0"

duplexer2@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
Expand Down Expand Up @@ -2672,7 +2680,7 @@ fbjs@^0.8.1, fbjs@^0.8.4:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"

fbjs@^0.8.16:
fbjs@^0.8.15, fbjs@^0.8.16:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
Expand Down Expand Up @@ -3302,6 +3310,10 @@ ignore@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"

immutable@~3.7.4:
version "3.7.6"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"

imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
Expand Down

0 comments on commit dff3e52

Please sign in to comment.