diff --git a/extensions/iframe.js b/extensions/iframe.js index e39a89af4d..6d67744416 100644 --- a/extensions/iframe.js +++ b/extensions/iframe.js @@ -4,12 +4,16 @@ // Context: "iframe" is an HTML element that lets websites embed other websites. // License: MIT AND MPL-2.0 +// Edited by izum00 + (function (Scratch) { "use strict"; - /** @type {HTMLIFrameElement|null} */ - let iframe = null; - let overlay = null; + /** @type {Object.} */ + const iframes = {}; + + // ブロックモードを管理する変数 (デフォルトは古いブロック) + let useNewBlocks = true; const featurePolicy = { accelerometer: "'none'", @@ -47,20 +51,17 @@ // The big one we don't want to include is allow-top-navigation ]; - let x = 0; - let y = 0; - let width = -1; // negative means default - let height = -1; // negative means default - let interactive = true; - let resizeBehavior = "scale"; - /** @type {string|number|boolean} */ - let latestMessage = ""; - - const updateFrameAttributes = () => { - if (!iframe) { + const getOverlayMode = (resizeBehavior) => + resizeBehavior === "scale" ? "scale-centered" : "manual"; + + const updateFrameAttributes = (id) => { + const iframeData = iframes[id]; + if (!iframeData || !iframeData.iframe) { return; } + const { iframe, x, y, width, height, interactive, resizeBehavior } = + iframeData; iframe.style.pointerEvents = interactive ? "auto" : "none"; const { stageWidth, stageHeight } = Scratch.vm.runtime; @@ -91,11 +92,8 @@ } }; - const getOverlayMode = () => - resizeBehavior === "scale" ? "scale-centered" : "manual"; - - const createFrame = (src) => { - iframe = document.createElement("iframe"); + const createFrame = (src, id) => { + const iframe = document.createElement("iframe"); iframe.style.width = "100%"; iframe.style.height = "100%"; iframe.style.border = "none"; @@ -108,183 +106,497 @@ .join("; ") ); iframe.setAttribute("allowtransparency", "true"); - iframe.setAttribute("allowtransparency", "true"); iframe.setAttribute("src", src); + iframe.setAttribute("data-iframe-id", id); + + const overlay = Scratch.renderer.addOverlay( + iframe, + getOverlayMode("scale") + ); + + iframes[id] = { + iframe, + overlay, + x: 0, + y: 0, + width: -1, + height: -1, + interactive: true, + resizeBehavior: "scale", + latestMessage: "", + }; + + updateFrameAttributes(id); + return id; + }; - overlay = Scratch.renderer.addOverlay(iframe, getOverlayMode()); - updateFrameAttributes(); + const closeFrame = (id) => { + const iframeData = iframes[id]; + if (iframeData) { + Scratch.renderer.removeOverlay(iframeData.iframe); + delete iframes[id]; + } }; - const closeFrame = () => { - if (iframe) { - Scratch.renderer.removeOverlay(iframe); - iframe = null; - overlay = null; + const getIframeData = (id) => { + if (!iframes[id]) { + // デフォルト値を持つ新しいiframeデータを作成(非表示) + iframes[id] = { + iframe: null, + overlay: null, + x: 0, + y: 0, + width: -1, + height: -1, + interactive: true, + resizeBehavior: "scale", + latestMessage: "", + }; } + return iframes[id]; }; window.addEventListener("message", (e) => { - if (iframe && iframe.contentWindow && e.source === iframe.contentWindow) { - latestMessage = - typeof e.data === "string" || - typeof e.data === "number" || - typeof e.data === "boolean" - ? e.data - : JSON.stringify(e.data); - Scratch.vm.runtime.startHats("iframe_whenMessage"); + // すべてのiframeをチェックしてメッセージの送信元を特定 + for (const id in iframes) { + const iframeData = iframes[id]; + if ( + iframeData.iframe && + iframeData.iframe.contentWindow && + e.source === iframeData.iframe.contentWindow + ) { + iframeData.latestMessage = + typeof e.data === "string" || + typeof e.data === "number" || + typeof e.data === "boolean" + ? e.data + : JSON.stringify(e.data); + Scratch.vm.runtime.startHats("iframe_whenMessage", { + IFRAME_ID: id, + }); + Scratch.vm.runtime.startHats("iframe_whenMessage_new", { + IFRAME_ID: id, + }); + break; + } } }); - Scratch.vm.on("STAGE_SIZE_CHANGED", updateFrameAttributes); + Scratch.vm.on("STAGE_SIZE_CHANGED", () => { + for (const id in iframes) { + updateFrameAttributes(id); + } + }); - Scratch.vm.runtime.on("RUNTIME_DISPOSED", closeFrame); + Scratch.vm.runtime.on("RUNTIME_DISPOSED", () => { + for (const id in iframes) { + closeFrame(id); + } + }); class IframeExtension { getInfo() { - return { - name: Scratch.translate("Iframe"), - id: "iframe", - blocks: [ - { - opcode: "display", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("show website [URL]"), - arguments: { - URL: { - type: Scratch.ArgumentType.STRING, - defaultValue: "https://extensions.turbowarp.org/hello.html", - }, + const oldBlocks = [ + { + opcode: "display_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show website [URL] as [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + URL: { + type: Scratch.ArgumentType.STRING, + defaultValue: "https://extensions.turbowarp.org/hello.html", + }, + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", }, }, - { - opcode: "displayHTML", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("show HTML [HTML]"), - arguments: { - HTML: { - type: Scratch.ArgumentType.STRING, - defaultValue: `

${Scratch.translate("It works!")}

`, - }, + }, + { + opcode: "displayHTML_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show HTML [HTML] as [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + HTML: { + type: Scratch.ArgumentType.STRING, + defaultValue: `

${Scratch.translate("It works!")}

`, + }, + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", }, }, - "---", - { - opcode: "show", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("show iframe"), + }, + "---", + { + opcode: "show_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show iframe [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, }, - { - opcode: "hide", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("hide iframe"), + }, + { + opcode: "hide_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("hide iframe [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, }, - { - opcode: "close", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("close iframe"), + }, + { + opcode: "close_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("close iframe [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, }, - "---", - { - opcode: "get", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("iframe [MENU]"), - arguments: { - MENU: { - type: Scratch.ArgumentType.STRING, - menu: "getMenu", - }, + }, + "---", + { + opcode: "get_new", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("iframe [ID] [MENU]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + MENU: { + type: Scratch.ArgumentType.STRING, + menu: "getMenu", }, }, - { - opcode: "setX", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe x position to [X]"), - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "0", - }, + }, + { + opcode: "setX_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe [ID] x position to [X]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", }, }, - { - opcode: "setY", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe y position to [Y]"), - arguments: { - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "0", - }, + }, + { + opcode: "setY_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe [ID] y position to [Y]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", }, }, - { - opcode: "setWidth", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe width to [WIDTH]"), - arguments: { - WIDTH: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: Scratch.vm.runtime.stageWidth, - }, + }, + { + opcode: "setWidth_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe [ID] width to [WIDTH]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + WIDTH: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: Scratch.vm.runtime.stageWidth, }, }, - { - opcode: "setHeight", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe height to [HEIGHT]"), - arguments: { - HEIGHT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: Scratch.vm.runtime.stageHeight, - }, + }, + { + opcode: "setHeight_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe [ID] height to [HEIGHT]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + HEIGHT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: Scratch.vm.runtime.stageHeight, }, }, - { - opcode: "setInteractive", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe interactive to [INTERACTIVE]"), - arguments: { - INTERACTIVE: { - type: Scratch.ArgumentType.STRING, - menu: "interactiveMenu", - }, + }, + { + opcode: "setInteractive_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate( + "set iframe [ID] interactive to [INTERACTIVE]" + ), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + INTERACTIVE: { + type: Scratch.ArgumentType.STRING, + menu: "interactiveMenu", }, }, - { - opcode: "setResize", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("set iframe resize behavior to [RESIZE]"), - arguments: { - RESIZE: { - type: Scratch.ArgumentType.STRING, - menu: "resizeMenu", - }, + }, + { + opcode: "setResize_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate( + "set iframe [ID] resize behavior to [RESIZE]" + ), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + RESIZE: { + type: Scratch.ArgumentType.STRING, + menu: "resizeMenu", }, }, - "---", - { - opcode: "sendMessage", - blockType: Scratch.BlockType.COMMAND, - text: Scratch.translate("send message [MESSAGE] to iframe"), - arguments: { - MESSAGE: { - type: Scratch.ArgumentType.STRING, - defaultValue: "hello", - }, + }, + "---", + { + opcode: "sendMessage_new", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("send message [MESSAGE] to iframe [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + MESSAGE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "hello", + }, + }, + }, + { + opcode: "whenMessage_new", + blockType: Scratch.BlockType.EVENT, + text: Scratch.translate("when message received from iframe"), + hideFromPalette: useNewBlocks, + isEdgeActivated: false, + }, + { + opcode: "iframeMessage_new", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("message from iframe [ID]"), + hideFromPalette: useNewBlocks, + arguments: { + ID: { + type: Scratch.ArgumentType.STRING, + defaultValue: "iframe1", + }, + }, + }, + { + opcode: "lastMessageId_new", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("ID of iframe that sent last message"), + hideFromPalette: useNewBlocks, + }, + ]; + + const newBlocks = [ + { + opcode: "display", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show website [URL]"), + hideFromPalette: !useNewBlocks, + arguments: { + URL: { + type: Scratch.ArgumentType.STRING, + defaultValue: "https://extensions.turbowarp.org/hello.html", + }, + }, + }, + { + opcode: "displayHTML", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show HTML [HTML]"), + hideFromPalette: !useNewBlocks, + arguments: { + HTML: { + type: Scratch.ArgumentType.STRING, + defaultValue: `

${Scratch.translate("It works!")}

`, + }, + }, + }, + "---", + { + opcode: "show", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("show iframe"), + hideFromPalette: !useNewBlocks, + }, + { + opcode: "hide", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("hide iframe"), + hideFromPalette: !useNewBlocks, + }, + { + opcode: "close", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("close iframe"), + hideFromPalette: !useNewBlocks, + }, + "---", + { + opcode: "get", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("iframe [MENU]"), + hideFromPalette: !useNewBlocks, + arguments: { + MENU: { + type: Scratch.ArgumentType.STRING, + menu: "getMenu", + }, + }, + }, + { + opcode: "setX", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe x position to [X]"), + hideFromPalette: !useNewBlocks, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + }, + }, + { + opcode: "setY", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe y position to [Y]"), + hideFromPalette: !useNewBlocks, + arguments: { + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + }, + }, + { + opcode: "setWidth", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe width to [WIDTH]"), + hideFromPalette: !useNewBlocks, + arguments: { + WIDTH: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: Scratch.vm.runtime.stageWidth, }, }, - { - opcode: "whenMessage", - blockType: Scratch.BlockType.EVENT, - text: Scratch.translate("when message received from iframe"), - isEdgeActivated: false, + }, + { + opcode: "setHeight", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe height to [HEIGHT]"), + hideFromPalette: !useNewBlocks, + arguments: { + HEIGHT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: Scratch.vm.runtime.stageHeight, + }, + }, + }, + { + opcode: "setInteractive", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe interactive to [INTERACTIVE]"), + hideFromPalette: !useNewBlocks, + arguments: { + INTERACTIVE: { + type: Scratch.ArgumentType.STRING, + menu: "interactiveMenu", + }, }, - { - opcode: "iframeMessage", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("iframe message"), + }, + { + opcode: "setResize", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("set iframe resize behavior to [RESIZE]"), + hideFromPalette: !useNewBlocks, + arguments: { + RESIZE: { + type: Scratch.ArgumentType.STRING, + menu: "resizeMenu", + }, + }, + }, + "---", + { + opcode: "sendMessage", + blockType: Scratch.BlockType.COMMAND, + text: Scratch.translate("send message [MESSAGE] to iframe"), + hideFromPalette: !useNewBlocks, + arguments: { + MESSAGE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "hello", + }, }, - ], + }, + { + opcode: "whenMessage", + blockType: Scratch.BlockType.EVENT, + text: Scratch.translate("when message received from iframe"), + hideFromPalette: !useNewBlocks, + isEdgeActivated: false, + }, + { + opcode: "iframeMessage", + blockType: Scratch.BlockType.REPORTER, + text: Scratch.translate("iframe message"), + hideFromPalette: !useNewBlocks, + }, + ]; + + const modeSwitchBlock = { + opcode: "switchMode", + blockType: Scratch.BlockType.BUTTON, + text: !useNewBlocks + ? Scratch.translate("Switch to Old Blocks [▶]") + : Scratch.translate("Switch to New Blocks [▶]"), + func: "switchMode", + }; + + return { + name: Scratch.translate("Iframe+"), + id: "iframeplus", + blocks: [modeSwitchBlock, "---", ...oldBlocks, ...newBlocks], menus: { getMenu: { acceptReporters: true, @@ -324,107 +636,306 @@ }; } + switchMode() { + useNewBlocks = !useNewBlocks; + // ブロックパレットを更新 + Scratch.vm.extensionManager.refreshBlocks(); + } + + // 新しいブロックの実装 (単一iframe用 - IDは"iframe"固定) async display({ URL }) { - closeFrame(); + const ID = "iframe"; + closeFrame(ID); if (await Scratch.canEmbed(URL)) { - createFrame(Scratch.Cast.toString(URL)); + createFrame(Scratch.Cast.toString(URL), ID); } } async displayHTML({ HTML }) { - closeFrame(); - const url = `data:text/html;,${encodeURIComponent( + const ID = "iframe"; + closeFrame(ID); + const url = `data:text/html;charset=utf-8,${encodeURIComponent( Scratch.Cast.toString(HTML) )}`; if (await Scratch.canEmbed(url)) { - createFrame(url); + createFrame(url, ID); } } show() { - if (iframe) { - iframe.style.display = ""; + const ID = "iframe"; + const iframeData = getIframeData(ID); + if (iframeData.iframe) { + iframeData.iframe.style.display = ""; } } hide() { - if (iframe) { - iframe.style.display = "none"; + const ID = "iframe"; + const iframeData = getIframeData(ID); + if (iframeData.iframe) { + iframeData.iframe.style.display = "none"; } } close() { - closeFrame(); + const ID = "iframe"; + closeFrame(ID); } get({ MENU }) { + const ID = "iframe"; MENU = Scratch.Cast.toString(MENU); + const iframeData = getIframeData(ID); + if (MENU === "url") { - if (iframe) return iframe.getAttribute("src"); + if (iframeData.iframe) return iframeData.iframe.getAttribute("src"); return ""; } else if (MENU === "visible") { - return !!iframe && iframe.style.display !== "none"; + return ( + !!iframeData.iframe && iframeData.iframe.style.display !== "none" + ); } else if (MENU === "x") { - return x; + return iframeData.x; } else if (MENU === "y") { - return y; + return iframeData.y; } else if (MENU === "width") { - return width >= 0 ? width : Scratch.vm.runtime.stageWidth; + return iframeData.width >= 0 + ? iframeData.width + : Scratch.vm.runtime.stageWidth; } else if (MENU === "height") { - return height >= 0 ? height : Scratch.vm.runtime.stageHeight; + return iframeData.height >= 0 + ? iframeData.height + : Scratch.vm.runtime.stageHeight; } else if (MENU === "interactive") { - return interactive; + return iframeData.interactive; } else if (MENU === "resize behavior") { - return resizeBehavior; + return iframeData.resizeBehavior; } else { return ""; } } setX({ X }) { - x = Scratch.Cast.toNumber(X); - updateFrameAttributes(); + const ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.x = Scratch.Cast.toNumber(X); + updateFrameAttributes(ID); } setY({ Y }) { - y = Scratch.Cast.toNumber(Y); - updateFrameAttributes(); + const ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.y = Scratch.Cast.toNumber(Y); + updateFrameAttributes(ID); } setWidth({ WIDTH }) { - width = Scratch.Cast.toNumber(WIDTH); - updateFrameAttributes(); + const ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.width = Scratch.Cast.toNumber(WIDTH); + updateFrameAttributes(ID); } setHeight({ HEIGHT }) { - height = Scratch.Cast.toNumber(HEIGHT); - updateFrameAttributes(); + const ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.height = Scratch.Cast.toNumber(HEIGHT); + updateFrameAttributes(ID); } setInteractive({ INTERACTIVE }) { - interactive = Scratch.Cast.toBoolean(INTERACTIVE); - updateFrameAttributes(); + const ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.interactive = Scratch.Cast.toBoolean(INTERACTIVE); + updateFrameAttributes(ID); } setResize({ RESIZE }) { + const ID = "iframe"; + const iframeData = getIframeData(ID); if (RESIZE === "scale" || RESIZE === "viewport") { - resizeBehavior = RESIZE; - if (overlay) { - overlay.mode = getOverlayMode(); + iframeData.resizeBehavior = RESIZE; + if (iframeData.overlay) { + iframeData.overlay.mode = getOverlayMode(RESIZE); Scratch.renderer._updateOverlays(); - updateFrameAttributes(); + updateFrameAttributes(ID); } } } sendMessage({ MESSAGE }) { - if (iframe && iframe.contentWindow) { - iframe.contentWindow.postMessage(MESSAGE, "*"); + const ID = "iframe"; + const iframeData = iframes[ID]; + if (iframeData && iframeData.iframe && iframeData.iframe.contentWindow) { + iframeData.iframe.contentWindow.postMessage(MESSAGE, "*"); } } iframeMessage() { - return latestMessage; + const ID = "iframe"; + const iframeData = getIframeData(ID); + return iframeData.latestMessage; + } + + // 古いブロックの実装 (複数iframe対応) + async display_new({ URL, ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + closeFrame(ID); + if (await Scratch.canEmbed(URL)) { + createFrame(Scratch.Cast.toString(URL), ID); + } + } + + async displayHTML_new({ HTML, ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + closeFrame(ID); + const url = `data:text/html;,${encodeURIComponent( + Scratch.Cast.toString(HTML) + )}`; + if (await Scratch.canEmbed(url)) { + createFrame(url, ID); + } + } + + show_new({ ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + if (iframeData.iframe) { + iframeData.iframe.style.display = ""; + } + } + + hide_new({ ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + if (iframeData.iframe) { + iframeData.iframe.style.display = "none"; + } + } + + close_new({ ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + closeFrame(ID); + } + + get_new({ ID, MENU }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + MENU = Scratch.Cast.toString(MENU); + const iframeData = getIframeData(ID); + + if (MENU === "url") { + if (iframeData.iframe) return iframeData.iframe.getAttribute("src"); + return ""; + } else if (MENU === "visible") { + return ( + !!iframeData.iframe && iframeData.iframe.style.display !== "none" + ); + } else if (MENU === "x") { + return iframeData.x; + } else if (MENU === "y") { + return iframeData.y; + } else if (MENU === "width") { + return iframeData.width >= 0 + ? iframeData.width + : Scratch.vm.runtime.stageWidth; + } else if (MENU === "height") { + return iframeData.height >= 0 + ? iframeData.height + : Scratch.vm.runtime.stageHeight; + } else if (MENU === "interactive") { + return iframeData.interactive; + } else if (MENU === "resize behavior") { + return iframeData.resizeBehavior; + } else { + return ""; + } + } + + setX_new({ ID, X }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.x = Scratch.Cast.toNumber(X); + updateFrameAttributes(ID); + } + + setY_new({ ID, Y }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.y = Scratch.Cast.toNumber(Y); + updateFrameAttributes(ID); + } + + setWidth_new({ ID, WIDTH }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.width = Scratch.Cast.toNumber(WIDTH); + updateFrameAttributes(ID); + } + + setHeight_new({ ID, HEIGHT }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.height = Scratch.Cast.toNumber(HEIGHT); + updateFrameAttributes(ID); + } + + setInteractive_new({ ID, INTERACTIVE }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + iframeData.interactive = Scratch.Cast.toBoolean(INTERACTIVE); + updateFrameAttributes(ID); + } + + setResize_new({ ID, RESIZE }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + if (RESIZE === "scale" || RESIZE === "viewport") { + iframeData.resizeBehavior = RESIZE; + if (iframeData.overlay) { + iframeData.overlay.mode = getOverlayMode(RESIZE); + Scratch.renderer._updateOverlays(); + updateFrameAttributes(ID); + } + } + } + + sendMessage_new({ ID, MESSAGE }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = iframes[ID]; + if (iframeData && iframeData.iframe && iframeData.iframe.contentWindow) { + iframeData.iframe.contentWindow.postMessage(MESSAGE, "*"); + } + } + + iframeMessage_new({ ID }) { + ID = Scratch.Cast.toString(ID); + if (!ID) ID = "iframe"; + const iframeData = getIframeData(ID); + return iframeData.latestMessage; + } + + lastMessageId_new() { + // 最後にメッセージを受信したiframeのIDを返す + for (const id in iframes) { + if (iframes[id].latestMessage !== "") { + return id; + } + } + return "iframe"; } }