-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iframed editor: support scripts #31873
Changes from all commits
3537def
d316b07
68121ee
7a17801
7245466
fcfafac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ import { | |
createPortal, | ||
useCallback, | ||
forwardRef, | ||
useEffect, | ||
useMemo, | ||
} from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { useMergeRefs } from '@wordpress/compose'; | ||
|
@@ -126,21 +128,33 @@ function setBodyClassName( doc ) { | |
} | ||
} | ||
|
||
/** | ||
* Sets the document head and default styles. | ||
* | ||
* @param {Document} doc Document to set the head for. | ||
* @param {string} head HTML to set as the head. | ||
*/ | ||
function setHead( doc, head ) { | ||
doc.head.innerHTML = | ||
// Body margin must be overridable by themes. | ||
'<style>body{margin:0}</style>' + head; | ||
function useParsedAssets( html ) { | ||
return useMemo( () => { | ||
const doc = document.implementation.createHTMLDocument( '' ); | ||
doc.body.innerHTML = html; | ||
return Array.from( doc.body.children ); | ||
}, [ html ] ); | ||
} | ||
|
||
function Iframe( { contentRef, children, head, headHTML, ...props }, ref ) { | ||
const [ iframeDocument, setIframeDocument ] = useState(); | ||
async function loadScript( doc, { id, src } ) { | ||
return new Promise( ( resolve, reject ) => { | ||
const script = doc.createElement( 'script' ); | ||
script.id = id; | ||
if ( src ) { | ||
script.src = src; | ||
script.onload = () => resolve(); | ||
script.onerror = () => reject(); | ||
} else { | ||
resolve(); | ||
} | ||
doc.head.appendChild( script ); | ||
} ); | ||
} | ||
|
||
function Iframe( { contentRef, children, head, ...props }, ref ) { | ||
const [ iframeDocument, setIframeDocument ] = useState(); | ||
const styles = useParsedAssets( window.__editorAssets.styles ); | ||
const scripts = useParsedAssets( window.__editorAssets.scripts ); | ||
const clearerRef = useBlockSelectionClearer(); | ||
const setRef = useCallback( ( node ) => { | ||
if ( ! node ) { | ||
|
@@ -161,15 +175,19 @@ function Iframe( { contentRef, children, head, headHTML, ...props }, ref ) { | |
contentRef.current = body; | ||
} | ||
|
||
setHead( contentDocument, headHTML ); | ||
setBodyClassName( contentDocument ); | ||
styleSheetsCompat( contentDocument ); | ||
bubbleEvents( contentDocument ); | ||
setBodyClassName( contentDocument ); | ||
setIframeDocument( contentDocument ); | ||
clearerRef( documentElement ); | ||
clearerRef( body ); | ||
|
||
scripts.reduce( | ||
( promise, script ) => | ||
promise.then( () => loadScript( contentDocument, script ) ), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This effectively serialises script loading, correct? Any reason for preferring this over parallel loading? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, otherwise a script might load before a dependency has loaded? It would be nice to load in parallel, but evaluate in series. Not sure how that would work though. I doesn't block rendering so it seems fine to me. We can polish this later on . There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, you're right. Parallelising isn't impossible, but we'd need a careful method to determine dependencies. |
||
Promise.resolve() | ||
); | ||
|
||
return true; | ||
} | ||
|
||
|
@@ -183,6 +201,25 @@ function Iframe( { contentRef, children, head, headHTML, ...props }, ref ) { | |
} ); | ||
}, [] ); | ||
|
||
useEffect( () => { | ||
if ( iframeDocument ) { | ||
styleSheetsCompat( iframeDocument ); | ||
} | ||
}, [ iframeDocument ] ); | ||
|
||
head = ( | ||
<> | ||
<style>{ 'body{margin:0}' }</style> | ||
{ styles.map( ( { tagName, href, id, rel, media }, index ) => { | ||
const TagName = tagName.toLowerCase(); | ||
return ( | ||
<TagName { ...{ href, id, rel, media } } key={ index } /> | ||
); | ||
} ) } | ||
{ head } | ||
</> | ||
); | ||
|
||
return ( | ||
<iframe | ||
{ ...props } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,7 +70,6 @@ function MaybeIframe( { | |
|
||
return ( | ||
<Iframe | ||
headHTML={ window.__editorStyles.html } | ||
head={ <EditorStyles styles={ styles } /> } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will Iframe's inputs be consolidated in the future? With this change, we now have:
It shouldn't block this PR, but it seems like something to address at some point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After this PR, we have one less? :) The hardcoded style was there before, it's the same a mini default stylesheet. |
||
ref={ ref } | ||
contentRef={ contentRef } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels important to either rename this function or split it up, as the name no longer reflects its purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ellatrix: there's still the function name:
gutenberg_extend_block_editor_styles_html