Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Support rendering Draft-js into iframe #1877

Closed
wants to merge 10 commits into from

Conversation

haikyuu
Copy link
Contributor

@haikyuu haikyuu commented Sep 21, 2018

Summary
This pull request adds support for draft-js usage inside iframes. There is another WIP PR which tries to achieve the same thing #765.

Note that this was mainly broken because instanceof does not check objects across iframes.
In other words (code) iframeElement instanceof Element === false while iframeElement instanceof iframeDocument.Element === true.

And the other reason is getSelection depends on the window object as well.

Checking if a node is instance of Element, HTMLElement ...

Depending on the context, we need a way to access the right iframe window object to check using instanceof.

Solutions D Pros 👍 Cons 👎 Shortcomings
attach the iframeWindow to global object, and use it to check whenever it's available 🛑 - Easy access to iframe document - breaks when there is an instance of Draft-js inside the iframe and another outside.- breaks when there are +2 iframes as well
get the document from the node itself and check - Works fine even when there are many iframes or editors in and out iframes - you can only access the global document when you have access to a node. (not needed here)
check the nodeType property instead (used in acusti's PR ) 🛑 - can't differentiate between Element and HTMLElement

Challenges

  • When pasting something from a different context. We get a body element which document object doesn't have a corresponding window / defaultView . It was fixed by adding another check.

Accessing the window or document object in other cases getSelection ...

Whenever the event is accessible, we use it to access the ownerDocument

Places skipped (they use the document and global objects)

  • getSafeBodyFromHTML : it creates a new document anyway
  • getTextContentFromFiles : it uses the global.fileReader

Other challenges

In order to fix some flow errors, i had to force casting node types in some places. Note that i only did this after instanceof checks, so it's safe. Those checks were not detected by flow because we use instanceof to check in iframe window or in the main window. One solution to fix this all together is to check nodes using a utility like fbjs' isNode but i prefer to keep the changes minimal.

Known issues

  • Inside an editor in an iframe: selecting some text and hitting cmd+b would apply the inline style but the selection will collapse. It happens only once, and doesn't happen outside an iframe. You can check it here and reproduce it in the sandbox
    draft-js-gif

Test Plan

I created a sandbox to test draft-js editor. It has 2 editors inside separate iframes, and one in the main window.

Copy link
Contributor

@claudiopro claudiopro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @haikyuu! I'll run some internal smoke tests to ensure we're not regressing with these changes. Otherwise looking quite good. Please take a look at my comments in the meantime, especially the issue with getAnonymizedEditorDOM.

return document.createTextNode(
const documentObject = getCorrectDocumentFromNode(node);

return documentObject.createTextNode(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you chain the call to getCorrectDocumentFromNode(node) without an intermediate assignment here and in function addPointToSelection, since you're not reusing the value?

@@ -76,11 +81,10 @@ function getAnonymizedEditorDOM(
): string {
// grabbing the DOM content of the Draft editor
let currentNode = node;
// this should only be used after checking with isElement
let castedNode: Element = (currentNode: any);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also assign it on line 91 when reassigning currentNode = currentNode.parentNode

);
if (isHTMLAnchorElement(node)) {
const castedNode: HTMLAnchorElement = (node: any);
return (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You lost a !! before the returned expression. I'd also suggest to return Boolean(<expression>) instead.

@@ -0,0 +1,14 @@
function isElement(node) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also check if node.nodeType === Node.ELEMENT_NODE

@@ -0,0 +1,14 @@
function isHTMLAnchorElement(node) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd implement this checking that, as @sophiebits suggested in another PR, isElement(node) && node.nodeName === 'A'

if (!node || !node.ownerDocument) {
return false;
}
if (!node.ownerDocument.defaultView) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isElement(node) && node.nodeName === 'IMG'

@claudiopro
Copy link
Contributor

I also found an issue when the iframed Editor has a placeholder prop, the placeholder text is rendered as a text block and the caret is placed on the next line.

Repro: https://codesandbox.io/s/nk90w2jv9j

@claudiopro
Copy link
Contributor

Ah, nevermind - that issue is caused by the absence of the Draft.css stylesheet 😄 apparently the placeholder is rendered using CSS.

@claudiopro
Copy link
Contributor

@haikyuu I PR'd an example based on your CodeSandbox demo: #1879

@claudiopro
Copy link
Contributor

@haikyuu do you need any help to address the review feedback? I'd like to merge this since it's in a good shape and there are many interested consumers!

@haikyuu
Copy link
Contributor Author

haikyuu commented Oct 21, 2018

I was quite busy these days. I'll fix them next week once i have some spare time👍

@claudiopro
Copy link
Contributor

Hi @haikyuu, would you have time to look into the finishing touch to this PR?

Several Draft.js users who are eager to embed editors in an iframe would be thankful for your efforts 😄

@marek-baranowski
Copy link

Hey @haikyuu, I'm also blocked by the iframe issue and I would love to see this PR merged :)

@haikyuu
Copy link
Contributor Author

haikyuu commented Nov 19, 2018

@marek-baranowski @claudiopro continued the work on #1938 👍

@niveditc
Copy link
Contributor

Closing this since it's continued on #1938 instead.

@niveditc niveditc closed this Jan 19, 2019
facebook-github-bot pushed a commit that referenced this pull request Nov 19, 2019
Summary:
**Summary**

Takes over and applies requested PR feedback to #1877 by haikyuu.

Refer to original PR for context and discussion.

**Test Plan**

Run some manual smoke tests on the editor running in an iframe as follows:

```
yarn
python3 -m http.server 8080 .
open http://localhost:8080/examples/draft-0-10-0/iframe/iframe.html
```
Pull Request resolved: #1938

Reviewed By: claudiopro

Differential Revision: D13137413

Pulled By: jack-arms

fbshipit-source-id: efcdbabc7d8d2aff4fbebc8b06c22d57756ebc12
mmissey pushed a commit to mmissey/draft-js that referenced this pull request Mar 24, 2020
…ve#1938)

Summary:
**Summary**

Takes over and applies requested PR feedback to facebookarchive#1877 by haikyuu.

Refer to original PR for context and discussion.

**Test Plan**

Run some manual smoke tests on the editor running in an iframe as follows:

```
yarn
python3 -m http.server 8080 .
open http://localhost:8080/examples/draft-0-10-0/iframe/iframe.html
```
Pull Request resolved: facebookarchive#1938

Reviewed By: claudiopro

Differential Revision: D13137413

Pulled By: jack-arms

fbshipit-source-id: efcdbabc7d8d2aff4fbebc8b06c22d57756ebc12
vilemj-Viclick pushed a commit to kontent-ai/draft-js that referenced this pull request Jul 16, 2020
…ve#1938)

Summary:
**Summary**

Takes over and applies requested PR feedback to facebookarchive#1877 by haikyuu.

Refer to original PR for context and discussion.

**Test Plan**

Run some manual smoke tests on the editor running in an iframe as follows:

```
yarn
python3 -m http.server 8080 .
open http://localhost:8080/examples/draft-0-10-0/iframe/iframe.html
```
Pull Request resolved: facebookarchive#1938

Reviewed By: claudiopro

Differential Revision: D13137413

Pulled By: jack-arms

fbshipit-source-id: efcdbabc7d8d2aff4fbebc8b06c22d57756ebc12
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants