diff --git a/src/background/executor.ts b/src/background/executor.ts index 09d11eaeaa..f2349ce94a 100644 --- a/src/background/executor.ts +++ b/src/background/executor.ts @@ -74,6 +74,10 @@ export async function waitForTargetByUrl(url: string): Promise { return promise; } +/** + * Run a brick in the window that opened the source window + * @param request + */ export async function requestRunInOpener( this: MessengerMeta, request: RunBlock @@ -91,6 +95,38 @@ export async function requestRunInOpener( return safelyRunBrick(opener, subRequest); } +/** + * Run a brick in the last window that was opened from the source window + * @see openTab + */ +export async function requestRunInTarget( + this: MessengerMeta, + request: RunBlock +): Promise { + const sourceTabId = this.trace[0].tab.id; + const target = tabToTarget.get(sourceTabId); + + if (!target) { + throw new BusinessError("Sender tab has no target"); + } + + const subRequest = { ...request, sourceTabId }; + return safelyRunBrick({ tabId: target }, subRequest); +} + +/** + * Run a brick in the topmost frame of the window/tab + */ +export async function requestRunInTop( + this: MessengerMeta, + request: RunBlock +): Promise { + const sourceTabId = this.trace[0].tab.id; + + const subRequest = { ...request, sourceTabId }; + return safelyRunBrick({ tabId: sourceTabId }, subRequest); +} + export async function requestRunInBroadcast( this: MessengerMeta, request: RunBlock @@ -124,21 +160,6 @@ export async function requestRunInBroadcast( return [...fulfilled].map(([, value]) => value); } -export async function requestRunInTarget( - this: MessengerMeta, - request: RunBlock -): Promise { - const sourceTabId = this.trace[0].tab.id; - const target = tabToTarget.get(sourceTabId); - - if (!target) { - throw new BusinessError("Sender tab has no target"); - } - - const subRequest = { ...request, sourceTabId }; - return safelyRunBrick({ tabId: target }, subRequest); -} - export async function openTab( this: MessengerMeta, createProperties: Tabs.CreateCreatePropertiesType diff --git a/src/background/messenger/api.ts b/src/background/messenger/api.ts index 01b7e74908..eeacc83fc8 100644 --- a/src/background/messenger/api.ts +++ b/src/background/messenger/api.ts @@ -76,6 +76,7 @@ export const requestRun = { onServer: getMethod("REQUEST_RUN_ON_SERVER", bg), inOpener: getMethod("REQUEST_RUN_IN_OPENER", bg), inTarget: getMethod("REQUEST_RUN_IN_TARGET", bg), + inTop: getMethod("REQUEST_RUN_IN_TOP", bg), inAll: getMethod("REQUEST_RUN_IN_ALL", bg), }; diff --git a/src/background/messenger/registration.ts b/src/background/messenger/registration.ts index de0fc55a43..5913945abd 100644 --- a/src/background/messenger/registration.ts +++ b/src/background/messenger/registration.ts @@ -35,6 +35,7 @@ import { requestRunInTarget, requestRunInBroadcast, waitForTargetByUrl, + requestRunInTop, } from "@/background/executor"; import * as registry from "@/registry/localRegistry"; import { ensureContentScript } from "@/background/util"; @@ -105,6 +106,7 @@ declare global { REQUEST_RUN_ON_SERVER: typeof requestRunOnServer; REQUEST_RUN_IN_OPENER: typeof requestRunInOpener; REQUEST_RUN_IN_TARGET: typeof requestRunInTarget; + REQUEST_RUN_IN_TOP: typeof requestRunInTop; REQUEST_RUN_IN_ALL: typeof requestRunInBroadcast; HTTP_REQUEST: typeof serializableAxiosRequest; @@ -174,6 +176,7 @@ export default function registerMessenger(): void { REQUEST_RUN_ON_SERVER: requestRunOnServer, REQUEST_RUN_IN_OPENER: requestRunInOpener, REQUEST_RUN_IN_TARGET: requestRunInTarget, + REQUEST_RUN_IN_TOP: requestRunInTop, REQUEST_RUN_IN_ALL: requestRunInBroadcast, HTTP_REQUEST: serializableAxiosRequest, diff --git a/src/blocks/types.ts b/src/blocks/types.ts index 9cc1ab15b5..1a2f2d735d 100644 --- a/src/blocks/types.ts +++ b/src/blocks/types.ts @@ -79,11 +79,18 @@ export type ReaderConfig = * - self: the current tab * - opener: the tab that opened the current tab * - target: the last tab that the current tab opened + * - top: the top-most frame in the window * - broadcast: all tabs that PixieBrix has access to (the result is returned as an array) * - remote: the server (currently only support identity, get, and http bricks) * @see {@link BlockConfig.window} */ -export type BlockWindow = "self" | "opener" | "target" | "broadcast" | "remote"; +export type BlockWindow = + | "self" + | "opener" + | "target" + | "top" + | "broadcast" + | "remote"; /** * Condition expression written in templateEngine for deciding if the step should be run. diff --git a/src/pageEditor/tabs/effect/BlockConfiguration.tsx b/src/pageEditor/tabs/effect/BlockConfiguration.tsx index fe63e931f2..d913614b2a 100644 --- a/src/pageEditor/tabs/effect/BlockConfiguration.tsx +++ b/src/pageEditor/tabs/effect/BlockConfiguration.tsx @@ -47,6 +47,7 @@ const targetOptions: Array> = [ { label: "Current Tab (self)", value: "self" }, { label: "Opener Tab (opener)", value: "opener" }, { label: "Target Tab (target)", value: "target" }, + { label: "Top-level Frame (top)", value: "top" }, { label: "All Tabs (broadcast)", value: "broadcast" }, { label: "Server (remote)", value: "remote" }, ]; diff --git a/src/runtime/reducePipeline.ts b/src/runtime/reducePipeline.ts index 0453a43afa..c923ff4b46 100644 --- a/src/runtime/reducePipeline.ts +++ b/src/runtime/reducePipeline.ts @@ -231,6 +231,10 @@ async function execute( return requestRun.inTarget(request); } + case "top": { + return requestRun.inTop(request); + } + case "broadcast": { return requestRun.inAll(request); }