diff --git a/lib/client-assets.php b/lib/client-assets.php index ab2cd25426a7ea..7e7f3800b791b2 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -708,7 +708,8 @@ function gutenberg_extend_block_editor_settings_with_fse_theme_flag( $settings ) * Sets the editor styles to be consumed by JS. */ function gutenberg_extend_block_editor_styles_html() { - $handles = array( + $script_handles = array(); + $style_handles = array( 'wp-block-editor', 'wp-block-library', 'wp-block-library-theme', @@ -719,26 +720,48 @@ function gutenberg_extend_block_editor_styles_html() { foreach ( $block_registry->get_all_registered() as $block_type ) { if ( ! empty( $block_type->style ) ) { - $handles[] = $block_type->style; + $style_handles[] = $block_type->style; } if ( ! empty( $block_type->editor_style ) ) { - $handles[] = $block_type->editor_style; + $style_handles[] = $block_type->editor_style; + } + + if ( ! empty( $block_type->script ) ) { + $script_handles[] = $block_type->script; } } - $handles = array_unique( $handles ); - $done = wp_styles()->done; + $style_handles = array_unique( $style_handles ); + $done = wp_styles()->done; ob_start(); wp_styles()->done = array(); - wp_styles()->do_items( $handles ); + wp_styles()->do_items( $style_handles ); wp_styles()->done = $done; - $editor_styles = wp_json_encode( array( 'html' => ob_get_clean() ) ); + $styles = ob_get_clean(); + + $script_handles = array_unique( $script_handles ); + $done = wp_scripts()->done; + + ob_start(); + + wp_scripts()->done = array(); + wp_scripts()->do_items( $script_handles ); + wp_scripts()->done = $done; + + $scripts = ob_get_clean(); + + $editor_assets = wp_json_encode( + array( + 'styles' => $styles, + 'scripts' => $scripts, + ) + ); - echo ""; + echo ""; } add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'gutenberg_extend_block_editor_styles_html' ); add_action( 'admin_footer-post.php', 'gutenberg_extend_block_editor_styles_html' ); diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 3570bb1bd6ad11..93d298632cfab6 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -6,6 +6,8 @@ import { createPortal, useCallback, forwardRef, + useEffect, + useMemo, } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { useMergeRefs } from '@wordpress/compose'; @@ -133,21 +135,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. - '' + 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 ) { @@ -168,15 +182,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 ) ), + Promise.resolve() + ); + return true; } @@ -190,6 +208,25 @@ function Iframe( { contentRef, children, head, headHTML, ...props }, ref ) { } ); }, [] ); + useEffect( () => { + if ( iframeDocument ) { + styleSheetsCompat( iframeDocument ); + } + }, [ iframeDocument ] ); + + head = ( + <> + + { styles.map( ( { tagName, href, id, rel, media }, index ) => { + const TagName = tagName.toLowerCase(); + return ( + + ); + } ) } + { head } + + ); + return (