Skip to content
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

Post editor: iframe for block-based themes #46212

Merged
merged 6 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/compat/wordpress-6.2/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ function gutenberg_resolve_assets_override() {
'block_editor_settings_all',
function( $settings ) {
// We must override what core is passing now.
$settings['__unstableResolvedAssets'] = gutenberg_resolve_assets_override();
$settings['__unstableResolvedAssets'] = gutenberg_resolve_assets_override();
$settings['__unstableIsBlockBasedTheme'] = wp_is_block_theme();
return $settings;
},
100
Expand Down
77 changes: 48 additions & 29 deletions packages/block-library/src/freeform/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import {
useBlockProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { debounce } from '@wordpress/compose';
import { debounce, useRefEffect } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { ToolbarGroup } from '@wordpress/components';
import { useEffect, useRef } from '@wordpress/element';
import { useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';

/**
* Internal dependencies
*/
import ConvertToBlocksButton from './convert-to-blocks-button';
import ModalEdit from './modal';

const { wp } = window;

Expand All @@ -36,17 +37,44 @@ function isTmceEmpty( editor ) {
return /^\n?$/.test( body.innerText || body.textContent );
}

export default function ClassicEdit( {
export default function FreeformEdit( props ) {
const { clientId } = props;
const canRemove = useSelect(
( select ) => select( blockEditorStore ).canRemoveBlock( clientId ),
[ clientId ]
);
const [ isIframed, setIsIframed ] = useState( false );
const ref = useRefEffect( ( element ) => {
setIsIframed( element.ownerDocument !== document );
}, [] );

return (
<>
{ canRemove && (
<BlockControls>
<ToolbarGroup>
<ConvertToBlocksButton clientId={ clientId } />
</ToolbarGroup>
</BlockControls>
) }
<div { ...useBlockProps( { ref } ) }>
{ isIframed ? (
<ModalEdit { ...props } />
) : (
<ClassicEdit { ...props } />
) }
</div>
</>
);
}

function ClassicEdit( {
clientId,
attributes: { content },
setAttributes,
onReplace,
} ) {
const { getMultiSelectedBlockClientIds } = useSelect( blockEditorStore );
const canRemove = useSelect(
( select ) => select( blockEditorStore ).canRemoveBlock( clientId ),
[ clientId ]
);
const didMount = useRef( false );

useEffect( () => {
Expand Down Expand Up @@ -225,28 +253,19 @@ export default function ClassicEdit( {
/* eslint-disable jsx-a11y/no-static-element-interactions */
return (
<>
{ canRemove && (
<BlockControls>
<ToolbarGroup>
<ConvertToBlocksButton clientId={ clientId } />
</ToolbarGroup>
</BlockControls>
) }
<div { ...useBlockProps() }>
<div
key="toolbar"
id={ `toolbar-${ clientId }` }
className="block-library-classic__toolbar"
onClick={ focus }
data-placeholder={ __( 'Classic' ) }
onKeyDown={ onToolbarKeyDown }
/>
<div
key="editor"
id={ `editor-${ clientId }` }
className="wp-block-freeform block-library-rich-text__tinymce"
/>
</div>
<div
key="toolbar"
id={ `toolbar-${ clientId }` }
className="block-library-classic__toolbar"
onClick={ focus }
data-placeholder={ __( 'Classic' ) }
onKeyDown={ onToolbarKeyDown }
/>
<div
key="editor"
id={ `editor-${ clientId }` }
className="wp-block-freeform block-library-rich-text__tinymce"
/>
</>
);
/* eslint-enable jsx-a11y/no-static-element-interactions */
Expand Down
111 changes: 111 additions & 0 deletions packages/block-library/src/freeform/modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* WordPress dependencies
*/
import { BlockControls, store } from '@wordpress/block-editor';
import {
ToolbarGroup,
ToolbarButton,
Modal,
Button,
} from '@wordpress/components';
import { useEffect, useState, RawHTML } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';

function ClassicEdit( props ) {
const styles = useSelect(
( select ) => select( store ).getSettings().styles
);
useEffect( () => {
const { baseURL, suffix, settings } = window.wpEditorL10n.tinymce;

window.tinymce.EditorManager.overrideDefaults( {
base_url: baseURL,
suffix,
} );

window.wp.oldEditor.initialize( props.id, {
tinymce: {
...settings,
height: 500,
setup( editor ) {
editor.on( 'init', () => {
const doc = editor.getDoc();
styles.forEach( ( { css } ) => {
const styleEl = doc.createElement( 'style' );
styleEl.innerHTML = css;
doc.head.appendChild( styleEl );
} );
} );
},
},
} );

return () => {
window.wp.oldEditor.remove( props.id );
};
}, [] );

return <textarea { ...props } />;
}

export default function ModalEdit( props ) {
const {
clientId,
attributes: { content },
setAttributes,
onReplace,
} = props;
const [ isOpen, setOpen ] = useState( false );
const id = `editor-${ clientId }`;
const label = __( 'Classic Edit' );

return (
<>
<BlockControls>
<ToolbarGroup>
<ToolbarButton onClick={ () => setOpen( true ) }>
{ label }
</ToolbarButton>
</ToolbarGroup>
</BlockControls>
{ content && <RawHTML>{ content }</RawHTML> }
{ ( isOpen || ! content ) && (
<Modal title={ label } __experimentalHideHeader={ true }>
<h2
style={ {
display: 'flex',
justifyContent: 'space-between',
} }
>
<div>{ label }</div>
<div>
<Button
onClick={ () =>
content ? setOpen( false ) : onReplace( [] )
}
>
{ __( 'Cancel' ) }
</Button>
<Button
isPrimary
onClick={ () => {
setAttributes( {
content:
window.wp.oldEditor.getContent(
id
),
} );
setOpen( false );
} }
>
{ __( 'Save' ) }
</Button>
</div>
</h2>
<ClassicEdit id={ id } defaultValue={ content } />
</Modal>
) }
</>
);
}
3 changes: 2 additions & 1 deletion packages/e2e-test-utils/src/create-reusable-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { insertBlock } from './inserter';
import { clickMenuItem } from './click-menu-item';
import { clickBlockToolbarButton } from './click-block-toolbar-button';
import { canvas } from './canvas';

/**
* Creates a simple reusable block with a paragraph block.
Expand Down Expand Up @@ -33,7 +34,7 @@ export const createReusableBlock = async ( content, title ) => {
);

// Check that we have a reusable block on the page
const block = await page.waitForSelector(
const block = await canvas().waitForSelector(
'.block-editor-block-list__block[data-type="core/block"]'
);
expect( block ).not.toBeNull();
Expand Down
25 changes: 13 additions & 12 deletions packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
visitSiteEditor,
enterEditMode,
deleteAllTemplates,
canvas,
} from '@wordpress/e2e-test-utils';

describe( 'Multi-entity save flow', () => {
Expand Down Expand Up @@ -94,8 +95,8 @@ describe( 'Multi-entity save flow', () => {
it( 'Save flow should work as expected.', async () => {
await createNewPost();
// Edit the page some.
await page.waitForSelector( '.editor-post-title' );
await page.click( '.editor-post-title' );
await canvas().waitForSelector( '.editor-post-title' );
await canvas().click( '.editor-post-title' );
await page.keyboard.type( 'Test Post...' );
await page.keyboard.press( 'Enter' );

Expand All @@ -110,8 +111,8 @@ describe( 'Multi-entity save flow', () => {

// Add a reusable block and edit it.
await createReusableBlock( 'Hi!', 'Test' );
await page.waitForSelector( 'p[data-type="core/paragraph"]' );
await page.click( 'p[data-type="core/paragraph"]' );
await canvas().waitForSelector( 'p[data-type="core/paragraph"]' );
await canvas().click( 'p[data-type="core/paragraph"]' );
await page.keyboard.type( 'Oh!' );

// Should trigger multi-entity save button once template part edited.
Expand Down Expand Up @@ -169,7 +170,7 @@ describe( 'Multi-entity save flow', () => {
} );

// Update the post.
await page.click( '.editor-post-title' );
await canvas().click( '.editor-post-title' );
await page.keyboard.type( '...more title!' );

// Verify update button is enabled.
Expand All @@ -182,9 +183,9 @@ describe( 'Multi-entity save flow', () => {
await assertExistence( saveA11ySelector, false );

// Update reusable block again.
await page.click( 'p[data-type="core/paragraph"]' );
await canvas().click( 'p[data-type="core/paragraph"]' );
// We need to click again due to the clickthrough overlays in reusable blocks.
await page.click( 'p[data-type="core/paragraph"]' );
await canvas().click( 'p[data-type="core/paragraph"]' );
await page.keyboard.type( 'R!' );

// Multi-entity saving should be enabled.
Expand All @@ -203,19 +204,19 @@ describe( 'Multi-entity save flow', () => {
);
const editableSiteTitleSelector =
'.wp-block-site-title a[contenteditable="true"]';
await page.waitForSelector( editableSiteTitleSelector );
await page.focus( editableSiteTitleSelector );
await canvas().waitForSelector( editableSiteTitleSelector );
await canvas().focus( editableSiteTitleSelector );
await page.keyboard.type( '...' );

await insertBlock( 'Site Tagline' );
// Wait for the placeholder.
await page.waitForXPath(
await canvas().waitForXPath(
'//span[@data-rich-text-placeholder="Write site tagline…"]'
);
const editableSiteTagLineSelector =
'.wp-block-site-tagline[contenteditable="true"]';
await page.waitForSelector( editableSiteTagLineSelector );
await page.focus( editableSiteTagLineSelector );
await canvas().waitForSelector( editableSiteTagLineSelector );
await canvas().focus( editableSiteTagLineSelector );
await page.keyboard.type( 'Just another WordPress site' );

await clickButton( 'Publish' );
Expand Down
6 changes: 5 additions & 1 deletion packages/edit-post/src/components/visual-editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export default function VisualEditor( { styles } ) {
editedPostTemplate = {},
wrapperBlockName,
wrapperUniqueId,
isBlockBasedTheme,
} = useSelect( ( select ) => {
const {
isFeatureActive,
Expand All @@ -137,7 +138,8 @@ export default function VisualEditor( { styles } ) {
_wrapperBlockName = 'core/post-content';
}

const supportsTemplateMode = getEditorSettings().supportsTemplateMode;
const editorSettings = getEditorSettings();
const supportsTemplateMode = editorSettings.supportsTemplateMode;
const canEditTemplate = select( coreStore ).canUser(
'create',
'templates'
Expand All @@ -155,6 +157,7 @@ export default function VisualEditor( { styles } ) {
: undefined,
wrapperBlockName: _wrapperBlockName,
wrapperUniqueId: getCurrentPostId(),
isBlockBasedTheme: editorSettings.__unstableIsBlockBasedTheme,
};
}, [] );
const { isCleanNewPost } = useSelect( editorStore );
Expand Down Expand Up @@ -336,6 +339,7 @@ export default function VisualEditor( { styles } ) {
>
<MaybeIframe
shouldIframe={
( isBlockBasedTheme && ! hasMetaBoxes ) ||
isTemplateMode ||
deviceType === 'Tablet' ||
deviceType === 'Mobile'
Expand Down
Loading