Skip to content

Commit

Permalink
FSE: load content in iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Oct 2, 2020
1 parent 16e98d4 commit 3986976
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 72 deletions.
37 changes: 37 additions & 0 deletions lib/edit-site-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,40 @@ function register_site_editor_homepage_settings() {
);
}
add_action( 'init', 'register_site_editor_homepage_settings', 10 );

/**
* Sets the editor styles to be consumed by JS.
*/
function gutenberg_extend_block_editor_styles_html() {
$handles = array(
'wp-block-editor',
'wp-block-library',
'wp-edit-blocks',
);

$block_registry = WP_Block_Type_Registry::get_instance();

foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
if ( ! empty( $block_type->style ) ) {
$handles[] = $block_type->style;
}

if ( ! empty( $block_type->editor_style ) ) {
$handles[] = $block_type->editor_style;
}
}

$handles = array_unique( $handles );
$done = wp_styles()->done;

ob_start();

wp_styles()->done = array();
wp_styles()->do_items( $handles );
wp_styles()->done = $done;

$editor_styles = wp_json_encode( array( 'html' => ob_get_clean() ) );

echo "<script>window.__editorStyles = $editor_styles</script>";
}
add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'gutenberg_extend_block_editor_styles_html' );
18 changes: 13 additions & 5 deletions packages/block-editor/src/components/block-list/block-popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Popover } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useShortcut } from '@wordpress/keyboard-shortcuts';
import { useViewportMatch } from '@wordpress/compose';
import { getScrollContainer } from '@wordpress/dom';

/**
* Internal dependencies
Expand Down Expand Up @@ -101,14 +102,16 @@ function BlockPopover( {

let node = blockNodes[ clientId ];

if ( capturingClientId ) {
node = document.getElementById( 'block-' + capturingClientId );
}

if ( ! node ) {
return null;
}

const { ownerDocument } = node;

if ( capturingClientId ) {
node = ownerDocument.getElementById( 'block-' + capturingClientId );
}

let anchorRef = node;

if ( hasMultiSelection ) {
Expand Down Expand Up @@ -141,6 +144,11 @@ function BlockPopover( {
const popoverPosition = showEmptyBlockSideInserter
? 'top left right'
: 'top right left';
const stickyEl = showEmptyBlockSideInserter
? undefined
: ownerDocument.defaultView.frameElement ||
getScrollContainer( node ) ||
ownerDocument.body;

return (
<Popover
Expand All @@ -150,7 +158,7 @@ function BlockPopover( {
focusOnMount={ false }
anchorRef={ anchorRef }
className="block-editor-block-list__block-popover"
__unstableSticky={ ! showEmptyBlockSideInserter }
__unstableSticky={ stickyEl }
__unstableSlotName="block-toolbar"
__unstableBoundaryParent
// Observe movement for block animations (especially horizontal).
Expand Down
105 changes: 88 additions & 17 deletions packages/components/src/popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ const FocusManaged = withConstrainedTabbing(
*/
const SLOT_NAME = 'Popover';

function offsetIframe( rect, ownerDocument ) {
const { defaultView } = ownerDocument;
const { frameElement } = defaultView;

if ( ! frameElement ) {
return rect;
}

const iframeRect = frameElement.getBoundingClientRect();

return new defaultView.DOMRect(
rect.left + iframeRect.left,
rect.top + iframeRect.top,
rect.width,
rect.height
);
}

function computeAnchorRect(
anchorRefFallback,
anchorRect,
Expand Down Expand Up @@ -71,12 +89,21 @@ function computeAnchorRect(
return;
}

if ( anchorRef instanceof window.Range ) {
return getRectangleFromRange( anchorRef );
if ( anchorRef.endContainer ) {
const { ownerDocument } = anchorRef.endContainer;
return offsetIframe(
getRectangleFromRange( anchorRef ),
ownerDocument
);
}

if ( anchorRef instanceof window.Element ) {
const rect = anchorRef.getBoundingClientRect();
const { ownerDocument } = anchorRef;

if ( ownerDocument ) {
const rect = offsetIframe(
anchorRef.getBoundingClientRect(),
ownerDocument
);

if ( shouldAnchorIncludePadding ) {
return rect;
Expand All @@ -88,13 +115,15 @@ function computeAnchorRect(
const { top, bottom } = anchorRef;
const topRect = top.getBoundingClientRect();
const bottomRect = bottom.getBoundingClientRect();
const rect = new window.DOMRect(
let rect = new window.DOMRect(
topRect.left,
topRect.top,
topRect.width,
bottomRect.bottom - topRect.top
);

rect = offsetIframe( rect, top.ownerDocument );

if ( shouldAnchorIncludePadding ) {
return rect;
}
Expand Down Expand Up @@ -240,6 +269,22 @@ function setClass( element, name, toggle ) {
}
}

function getAnchorDocument( anchor ) {
if ( ! anchor ) {
return;
}

if ( anchor.endContainer ) {
return anchor.endContainer.ownerDocument;
}

if ( anchor.top ) {
return anchor.top.ownerDocument;
}

return anchor.ownerDocument;
}

const Popover = ( {
headerTitle,
onClose,
Expand Down Expand Up @@ -402,42 +447,68 @@ const Popover = ( {

refresh();

const { ownerDocument } = containerRef.current;
const { defaultView } = ownerDocument;

/*
* There are sometimes we need to reposition or resize the popover that
* are not handled by the resize/scroll window events (i.e. CSS changes
* in the layout that changes the position of the anchor).
*
* For these situations, we refresh the popover every 0.5s
*/
const intervalHandle = window.setInterval( refresh, 500 );
const intervalHandle = defaultView.setInterval( refresh, 500 );

let rafId;

const refreshOnAnimationFrame = () => {
window.cancelAnimationFrame( rafId );
rafId = window.requestAnimationFrame( refresh );
defaultView.cancelAnimationFrame( rafId );
rafId = defaultView.requestAnimationFrame( refresh );
};

// Sometimes a click trigger a layout change that affects the popover
// position. This is an opportunity to immediately refresh rather than
// at the interval.
window.addEventListener( 'click', refreshOnAnimationFrame );
window.addEventListener( 'resize', refresh );
window.addEventListener( 'scroll', refresh, true );
defaultView.addEventListener( 'click', refreshOnAnimationFrame );
defaultView.addEventListener( 'resize', refresh );
defaultView.addEventListener( 'scroll', refresh, true );

const anchorDocument = getAnchorDocument( anchorRef );

if ( anchorDocument && anchorDocument !== ownerDocument ) {
anchorDocument.defaultView.addEventListener( 'resize', refresh );
anchorDocument.defaultView.addEventListener(
'scroll',
refresh,
true
);
}

let observer;

if ( __unstableObserveElement ) {
observer = new window.MutationObserver( refresh );
observer = new defaultView.MutationObserver( refresh );
observer.observe( __unstableObserveElement, { attributes: true } );
}

return () => {
window.clearInterval( intervalHandle );
window.removeEventListener( 'resize', refresh );
window.removeEventListener( 'scroll', refresh, true );
window.removeEventListener( 'click', refreshOnAnimationFrame );
window.cancelAnimationFrame( rafId );
defaultView.clearInterval( intervalHandle );
defaultView.removeEventListener( 'resize', refresh );
defaultView.removeEventListener( 'scroll', refresh, true );
defaultView.removeEventListener( 'click', refreshOnAnimationFrame );
defaultView.cancelAnimationFrame( rafId );

if ( anchorDocument && anchorDocument !== ownerDocument ) {
anchorDocument.defaultView.removeEventListener(
'resize',
refresh
);
anchorDocument.defaultView.removeEventListener(
'scroll',
refresh,
true
);
}

if ( observer ) {
observer.disconnect();
Expand Down
9 changes: 1 addition & 8 deletions packages/components/src/popover/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* WordPress dependencies
*/
import { getScrollContainer } from '@wordpress/dom';

/**
* Module constants
*/
Expand Down Expand Up @@ -163,9 +158,7 @@ export function computePopoverYAxisPosition(
const { height } = contentSize;

if ( sticky ) {
const scrollContainerEl =
getScrollContainer( anchorRef ) || document.body;
const scrollRect = scrollContainerEl.getBoundingClientRect();
const scrollRect = sticky.getBoundingClientRect();
const stickyPosition = scrollRect.top + height - relativeOffsetTop;

if ( anchorRect.top <= stickyPosition ) {
Expand Down
22 changes: 20 additions & 2 deletions packages/compose/src/hooks/use-keyboard-shortcut/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import { includes, castArray } from 'lodash';
/**
* WordPress dependencies
*/
import { useEffect, useRef } from '@wordpress/element';
import {
useEffect,
useRef,
createContext,
useContext,
} from '@wordpress/element';

/**
* A block selection object.
Expand All @@ -21,6 +26,8 @@ import { useEffect, useRef } from '@wordpress/element';
* @property {Object} [target] React reference to the DOM element used to catch the keyboard event.
*/

const WindowContext = createContext();

/**
* Return true if platform is MacOS.
*
Expand Down Expand Up @@ -52,18 +59,27 @@ function useKeyboardShortcut(
eventName = 'keydown',
isDisabled = false, // This is important for performance considerations.
target,
altWindow,
} = {}
) {
const currentCallback = useRef( callback );
useEffect( () => {
currentCallback.current = callback;
}, [ callback ] );
const win = useContext( WindowContext );

useEffect( () => {
if ( isDisabled ) {
return;
}
const mousetrap = new Mousetrap( target ? target.current : document );

let node = ( altWindow || win || window ).document;

if ( target && target.current ) {
node = target.current;
}

const mousetrap = new Mousetrap( node );
castArray( shortcuts ).forEach( ( shortcut ) => {
const keys = shortcut.split( '+' );
// Determines whether a key is a modifier by the length of the string.
Expand Down Expand Up @@ -100,4 +116,6 @@ function useKeyboardShortcut(
}, [ shortcuts, bindGlobal, eventName, target, isDisabled ] );
}

useKeyboardShortcut.WindowContext = WindowContext;

export default useKeyboardShortcut;
1 change: 1 addition & 0 deletions packages/e2e-test-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ result that appears. It then waits briefly for the block list to update.
_Parameters_

- _searchTerm_ `string`: The text to search the inserter for.
- _frame_ `Object`:

<a name="insertBlockDirectoryBlock" href="#insertBlockDirectoryBlock">#</a> **insertBlockDirectoryBlock**

Expand Down
11 changes: 7 additions & 4 deletions packages/e2e-test-utils/src/inserter.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ async function toggleGlobalBlockInserter() {

/**
* Retrieves the document container by css class and checks to make sure the document's active element is within it
*
* @param {Object} frame
*/
async function waitForInserterCloseAndContentFocus() {
await page.waitForFunction( () =>
async function waitForInserterCloseAndContentFocus( frame = page ) {
await frame.waitForFunction( () =>
document.body
.querySelector( '.block-editor-block-list__layout' )
.contains( document.activeElement )
Expand Down Expand Up @@ -124,15 +126,16 @@ export async function searchForReusableBlock( searchTerm ) {
* result that appears. It then waits briefly for the block list to update.
*
* @param {string} searchTerm The text to search the inserter for.
* @param {Object} frame
*/
export async function insertBlock( searchTerm ) {
export async function insertBlock( searchTerm, frame ) {
await searchForBlock( searchTerm );
const insertButton = (
await page.$x( `//button//span[contains(text(), '${ searchTerm }')]` )
)[ 0 ];
await insertButton.click();
// We should wait until the inserter closes and the focus moves to the content.
await waitForInserterCloseAndContentFocus();
await waitForInserterCloseAndContentFocus( frame );
}

/**
Expand Down
Loading

0 comments on commit 3986976

Please sign in to comment.