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

Multiple blocks on the same page #175

Merged
merged 11 commits into from
Feb 2, 2023
8 changes: 4 additions & 4 deletions frontend/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,26 @@ declare global {

export type BlockProps = Omit<BaseBlockProps, "iframeUrl">;

export function renderBlock(containerId: string, props: BlockProps) {
export function renderBlock(containerElement: HTMLElement, props: BlockProps) {
const blockProps: BaseBlockProps = {
...props,
iframeUrl: getIframeUrl(),
};

const element = createElement(Block, blockProps);
render(element, document.getElementById(containerId));
render(element, containerElement);
}

export type PopupProps = Omit<BasePopupProps, "iframeUrl">;

export function renderPopup(containerId: string, props: PopupProps) {
export function renderPopup(containerElement: HTMLElement, props: PopupProps) {
const popupProps: BasePopupProps = {
...props,
iframeUrl: getIframeUrl(),
};

const element = createElement(Popup, popupProps);
render(element, document.getElementById(containerId));
render(element, containerElement);
}

export function getIframeUrl(): URL {
Expand Down
44 changes: 22 additions & 22 deletions frontend/block/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,29 @@ export default function Edit(props: Props): WPElement {
return (
<>
<InspectorControls attributes={attributes} setAttributes={setAttributes}/>
<div {...useBlockProps()}>
<ResizableBox
size={{
width: "100%",
height: parsedAttributes.height ? parsedAttributes.height.toString() : "600px",
}}
enable={{
top: false,
right: false,
bottom: true,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
}}
onResizeStop={(_event, _direction, elt) => {
setAttributes({ height: { value: elt.clientHeight, unit: "px" } });
}}
>
<ResizableBox
size={{
width: "100%",
height: parsedAttributes.height ? parsedAttributes.height.toString() : "600px",
}}
enable={{
top: false,
right: false,
bottom: true,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
}}
onResizeStop={(_event, _direction, elt) => {
setAttributes({ height: { value: elt.clientHeight, unit: "px" } });
}}
>
<div {...useBlockProps()}>
<Block {...blockProps}/>
</ResizableBox>
</div>
</div>
</ResizableBox>
</>
);
}
53 changes: 33 additions & 20 deletions frontend/block/view.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
import { BlockProps, renderBlock } from "../app";

declare global {
interface Window {
ChatrixBlockConfig: {
containerId: string,
attributes: object,
window.addEventListener('DOMContentLoaded', () => {
renderAllBlocks().catch(error => {
console.error(error);
});
});

async function renderAllBlocks() {
// See https://github.com/Automattic/chatrix/issues/161 for why we introduce a delay here.
await introduceDelayInMilliseconds(1);

const containers = <HTMLCollectionOf<HTMLElement>>document.getElementsByClassName('wp-block-automattic-chatrix');
for (const container of containers) {
const config = getConfigFromDataAttribute(container);
const props: BlockProps = {
attributes: config.attributes,
};

renderBlock(container, props);
}
}

window.addEventListener('DOMContentLoaded', () => {
const config = window.ChatrixBlockConfig;
if (!config) {
throw "ChatrixBlockConfig is not defined";
/**
* The container element has a data-attribute that contains the config as encoded data.
* This function parses that data-attribute into an object.
*/
function getConfigFromDataAttribute(container: HTMLElement): BlockConfig {
const dataString = decodeURIComponent(container.dataset?.chatrixBlockConfig ?? '');
if (dataString === '') {
throw "Data attribute for chatrix block was not found, or is empty";
}

const containerId = config.containerId;
const container = document.getElementById(containerId);
if (!container) {
throw `element with id ${containerId} was not found`;
}
return JSON.parse(dataString);
}

const props: BlockProps = {
attributes: config.attributes,
};
interface BlockConfig {
attributes: object,
}

// See https://github.com/Automattic/chatrix/issues/161 for why we use a timeout here.
setTimeout( () => renderBlock(containerId, props), 1 );
});
async function introduceDelayInMilliseconds(delay: number) {
return new Promise(resolve => setTimeout(resolve, delay));
}
4 changes: 2 additions & 2 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
iframeUrl: window.origin,
};

renderBlock("root-block", {
renderBlock(document.getElementById("root-block"), {
attributes: {
defaultHomeserver: env.VITE_HOMESERVER,
roomId: env.VITE_ROOM_ID,
}
});

renderPopup("root-popup", {
renderPopup(document.getElementById("root-popup"), {
defaultHomeserver: env.VITE_HOMESERVER,
roomId: env.VITE_ROOM_ID,
});
Expand Down
15 changes: 3 additions & 12 deletions src/Block/block.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,21 @@ function () use ( $block_json_path ) {
}

function render( array $attributes ): string {
$handle = 'chatrix-block-config';
$container_id = 'wp-block-automattic-chatrix-container';

$json_data = wp_json_encode(
array(
'containerId' => $container_id,
'attributes' => $attributes,
'attributes' => $attributes,
)
);

wp_register_script( $handle, '', array(), automattic_chatrix_version(), true );
wp_add_inline_script( $handle, "window.ChatrixBlockConfig = $json_data;", 'before' );
wp_enqueue_script( $handle );

ob_start();
?>
<div <?php echo wp_kses_data( get_block_wrapper_attributes() ); ?> id="<?php echo esc_attr( $container_id ); ?>">
<?php // Iframe will be rendered here. ?>
<div <?php echo wp_kses_data( get_block_wrapper_attributes() ); ?> data-chatrix-block-config="<?php echo rawurlencode( $json_data ); ?>">
<?php // The <Block> component will be rendered here. ?>
</div>
<?php
return ob_get_clean();
}


function parse_block_json( string $block_json_path ): array {
// phpcs discourages file_get_contents for remote URLs, and recommends using wp_remote_get().
// However, here we're dealing with a path to a file on disk, so we ignore phpcs's warning.
Expand Down
2 changes: 1 addition & 1 deletion src/Popup/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
container.id = "chatrix-popup-container";
document.body.appendChild(container);

Chatrix.renderPopup(container.id, {
Chatrix.renderPopup(container, {
defaultHomeserver: config.defaultHomeserver,
roomId: config.roomId,
});
Expand Down