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

feat(web): plugin playground presets extension to extension messenger #1367

Merged
6 changes: 5 additions & 1 deletion web/src/beta/features/PluginPlayground/Code/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Visualizer from "@reearth/beta/features/Visualizer";
import { useNotification } from "@reearth/services/state";
import * as yaml from "js-yaml";
import { ComponentProps, useCallback, useState } from "react";
import { v4 } from "uuid";

import { Story } from "../../Visualizer/Crust/StoryPanel/types";
import { WidgetLocation } from "../../Visualizer/Crust/Widgets/types";
Expand Down Expand Up @@ -121,7 +122,10 @@ export default ({ files, resetVisualizer }: Props) => {
widgets: [
...(areaAlignSystem.widgets ?? []),
{
id: cur.id,
id: v4(),
mulengawilfred marked this conversation as resolved.
Show resolved Hide resolved
name: cur.name,
extensionId: cur.id,
pluginId: ymlJson.id,
__REEARTH_SOURCECODE: file.sourceCode,
extended
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import { FileType, PluginType } from "../../constants";
import { PRESET_PLUGIN_COMMON_STYLE } from "../common";

// YAML File Definition
const yamlFile: FileType = {
id: "extension-to-extension-messenger-reearth-yml",
title: "reearth.yml",
sourceCode: `id: extension-to-extension-messenger-plugin
name: Extension To Extension Messenger
version: 1.0.0
extensions:
- id: extension-1
type: widget
name: Extension 1
description: Extension 1 Widget
- id: extension-2
type: widget
name: Extension 2
description: Extension 2 Widget
`,
disableEdit: true,
disableDelete: true
};

// Extension 1 Widget Source Code
const extension1SourceCode = `
reearth.ui.show(\`
${PRESET_PLUGIN_COMMON_STYLE}
<style>
input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
flex-grow: 1;
}

button {
padding: 8px 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

button:hover {
background: #45a049;
}

.received {
background: white;
padding: 10px;
border-radius: 4px;
margin-top: 10px;
}

.messages-container {
min-height: 50px;
margin-top: 10px;
}

.message {
padding: 8px;
margin: 4px 0;
background: #f8f9fa;
border-radius: 4px;
}
</style>
airslice marked this conversation as resolved.
Show resolved Hide resolved

<div id="wrapper">
<h2>Extension 1</h2>
<div class="flex-center">
<input id="messageInput" type="text" placeholder="Enter message"/>
<button id="sendButton">Send</button>
</div>
<h3>Received Messages</h3>
<div class="received">
<div id="messagesContainer" class="messages-container"></div>
</div>
</div>

<script>
// Listen for UI button clicks and send message to extension
document.getElementById("sendButton").addEventListener("click", () => {
const input = document.getElementById("messageInput");
const message = input.value.trim();
if (message) {
// Send message from UI to extension
parent.postMessage({ type: "send", message }, "*");
input.value = "";
}
});
airslice marked this conversation as resolved.
Show resolved Hide resolved

// Listen for messages from extension to update UI
window.addEventListener("message", (e) => {
const msg = e.data;
if (msg.type === "received") {
const container = document.getElementById("messagesContainer");
const div = document.createElement("div");
div.textContent = msg.message;
div.style.margin = "4px 0";
container.appendChild(div);
}
});
airslice marked this conversation as resolved.
Show resolved Hide resolved
</script>
\`);

// Handle messages from UI to send to other extension
reearth.extension.on("message", msg => {
if (msg.type === "send") {
const extensions = reearth.extension.list;
const target = extensions.find(ext => ext.extensionId === "extension-2");
if (target) {
reearth.extension.postMessage(target.id, msg.message);
}
}
});

// Handle messages received from other extension
reearth.extension.on("extensionMessage", msg => {
reearth.ui.postMessage({
type: "received",
message: msg.data
});
});`;

// Extension 2 Widget Source Code
const extension2SourceCode = `
reearth.ui.show(\`
${PRESET_PLUGIN_COMMON_STYLE}
<style>
input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
flex-grow: 1;
}

button {
padding: 8px 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

button:hover {
background: #45a049;
}

.received {
background: white;
padding: 10px;
border-radius: 4px;
margin-top: 10px;
}

.messages-container {
min-height: 50px;
margin-top: 10px;
}

.message {
padding: 8px;
margin: 4px 0;
background: #f8f9fa;
border-radius: 4px;
}
</style>

<div id="wrapper">
<h2>Extension 2</h2>
<div class="flex-center">
<input id="messageInput" type="text" placeholder="Enter message"/>
<button id="sendButton">Send</button>
</div>
<h3>Received Messages</h3>
<div class="received">
<div id="messagesContainer" class="messages-container"></div>
</div>
</div>

<script>
document.getElementById("sendButton").addEventListener("click", () => {
const input = document.getElementById("messageInput");
const message = input.value.trim();
if (message) {
parent.postMessage({ type: "send", message }, "*");
input.value = "";
}
});

window.addEventListener("message", (e) => {
const msg = e.data;
if (msg.type === "received") {
const container = document.getElementById("messagesContainer");
const div = document.createElement("div");
div.textContent = msg.message;
div.style.margin = "4px 0";
container.appendChild(div);
}
});
</script>
\`);

// Note: Re:Earth visualizer requires using msg.data for message content
// and extensionId for finding extensions

// Handle messages from UI to send to other extension
reearth.extension.on("message", msg => {
if (msg.type === "send") {
const extensions = reearth.extension.list;
const target = extensions.find(ext => ext.extensionId === "extension-1");
if (target) {
reearth.extension.postMessage(target.id, msg.message);
}
}
});

// Handle messages received from other extension
reearth.extension.on("extensionMessage", msg => {
reearth.ui.postMessage({
type: "received",
message: msg.data
});
});`;
OpeDada marked this conversation as resolved.
Show resolved Hide resolved

// Widget File Definitions
const extension1File: FileType = {
id: "extension-to-extension-messenger-extension1",
title: "extension-1.js",
sourceCode: extension1SourceCode
};

const extension2File: FileType = {
id: "extension-to-extension-messenger-extension2",
title: "extension-2.js",
sourceCode: extension2SourceCode
};

// Plugin Definition
export const extensionExtensionMessenger: PluginType = {
id: "extension-to-extension-messenger",
title: "Extension To Extension Messenger",
files: [yamlFile, extension1File, extension2File]
};
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,43 @@ const widgetFile: FileType = {
button:hover {
background: #45a049;
}

#info-section {
margin: 20px 0;
text-align: left;
}

#info-toggle {
padding: 6px 12px; /* Smaller button */
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 12px; /* Smaller text */
}

#info-content {
background: #f9f9f9; /* Light gray background */
padding: 10px;
border-radius: 5px;
margin-top: 15px; /* Space between button and content */
font-size: 14px;
line-height: 1.4;
}
</style>

<div id="wrapper">
<h2>Coordinate Viewer</h2>
<div id="info-section">
<button id="info-toggle">Show Info</button>
<div id="info-content" style="display: none;">
<strong>How to use this plugin:</strong><br>
1. Click anywhere on the map to see its coordinates<br>
2. Click the "Fly to Position" button to move the camera to that location<br>
3. Coordinates update dynamically when you click anywhere on the map<br><br>
</div>
</div>
<div class="coordinates">
<p>Latitude: <span id="lat" class="coordinate-value">-</span>°</p>
<p>Longitude: <span id="lng" class="coordinate-value">-</span>°</p>
Expand Down Expand Up @@ -89,6 +122,14 @@ const widgetFile: FileType = {
alt: 1000 // Fixed camera height for better viewing
}, "*");
});

// Toggle info section
document.getElementById("info-toggle").addEventListener("click", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I click the show info button in the ui-extension-messenger plugin, the widget disappears for me. Does the same happen for you @OpeDada ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's still the iframe auto resize bug. We could fix that in another PR i think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No , it just extends downwards for me. Maybe you can show me?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Will resolve this for now

const infoContent = document.getElementById("info-content");
const isHidden = infoContent.style.display === "none";
infoContent.style.display = isHidden ? "block" : "none";
document.getElementById("info-toggle").textContent = isHidden ? "Hide Info" : "Show Info";
});
</script>
\`);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { PluginType } from "../constants";

import { extensionExtensionMessenger } from "./communication/extensionExtensionMessenger";
import { uiExtensionMessenger } from "./communication/uiExtensionMessenger";
import { myPlugin } from "./custom/myPlugin";
import { add3dTiles } from "./layers/add-3Dtiles";
import { addCsv } from "./layers/add-csv";
Expand All @@ -13,7 +15,6 @@ import { hideFlyToDeleteLayer } from "./layers/hideFlyToDeleteLayer";
import { header } from "./ui/header";
import { responsivePanel } from "./ui/responsivePanel";
import { sidebar } from "./ui/sidebar";
import { uiExtensionMessenger } from "./ui/uiExtensionMessenger";

type PresetPluginCategory = {
id: string;
Expand All @@ -37,7 +38,7 @@ export const presetPlugins: PresetPlugins = [
{
id: "communication",
title: "Communication",
plugins: [uiExtensionMessenger]
plugins: [uiExtensionMessenger, extensionExtensionMessenger]
},
{
id: "viewerScene",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export function usePluginAPI({
uiEvents.current = events<UIEventType>();
modalEvents.current = events<ModalEventType>();
popupEvents.current = events<PopupEventType>();
extensionEvents.current = events<ExtensionEventType>();

initAndMergeEvents(ctx.viewerEvents, viewerEventsRef, [
"click",
Expand Down
Loading