-
Notifications
You must be signed in to change notification settings - Fork 593
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Teacher tool: set up infrastructure to send messages to iframe (#9811)
* makecodeframe only holds ui, message handling for iframe split into the makecodeeditor service, file made for the transform * successfully sending message to set high contrast to the iframe when the evaluate button is pressed * cleaned up a bit * do something with the results of sending the message * consolidated ref logic in the service, got rid of extra logic in editor container * got rid of the editor container, it doesn't do anything meaningful anymore * got rid of the load event listener * changed ref handling, some minor changes in the service * no longer exposing sendMessageAsync * pushing messages to the queue even if the iframe isn't ready yet * changed functions from anonymous to declarative * fixed set editor ref logic, added check to see if message is undefined * upgrade codeql analysis to v2
- Loading branch information
Showing
8 changed files
with
97 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,141 +1,21 @@ | ||
/// <reference path="../../../built/pxteditor.d.ts" /> | ||
import * as React from "react"; | ||
import { useState, useEffect, useRef } from "react"; | ||
import { ProgressBar } from "react-common/components/controls/ProgressBar"; | ||
import { setEditorRef } from "../services/makecodeEditorService"; | ||
interface MakeCodeFrameProps { | ||
pageSourceUrl: string; | ||
highContrast?: boolean; | ||
onFrameOpen: () => void; | ||
onFrameClose: () => void; | ||
tutorialEventHandler?: (event: pxt.editor.EditorMessageTutorialEventRequest) => void; | ||
} | ||
|
||
type FrameState = "loading" | "no-project" | "opening-project" | "project-open" | "closing-project"; | ||
|
||
interface PendingMessage { | ||
original: pxt.editor.EditorMessageRequest; | ||
handler: (response: any) => void; | ||
} | ||
|
||
export const MakeCodeFrame: React.FC<MakeCodeFrameProps> = | ||
( { pageSourceUrl, | ||
highContrast, | ||
onFrameClose, | ||
onFrameOpen | ||
} ) => { | ||
let ref: HTMLIFrameElement | undefined; | ||
const messageQueue: pxt.editor.EditorMessageRequest[] = []; | ||
let nextId: number = 0; | ||
let pendingMessages: {[index: string]: PendingMessage} = {}; | ||
const [frameState, setFrameState] = useState<FrameState>("loading"); | ||
const [loadPercent, setLoadPercent] = useState(0); | ||
const [workspaceReady, setWorkspaceReady] = useState(false); | ||
|
||
let frameRef = useRef<HTMLIFrameElement>(null); | ||
|
||
useEffect(() => { | ||
// logic we want to do when the iframe is loaded | ||
if (ref && ref.contentWindow) { | ||
window.addEventListener("message", onMessageReceived); | ||
ref.addEventListener("load", handleFrameReload) | ||
|
||
} | ||
|
||
// logic we want when the iframe unmounts | ||
return () => { | ||
window.removeEventListener("message", onMessageReceived); | ||
if (ref && ref.contentWindow) { | ||
ref.removeEventListener("load", handleFrameReload) | ||
} | ||
} | ||
}, []) | ||
|
||
useEffect(() => { | ||
sendMessageAsync({ | ||
type: "pxteditor", | ||
action: "sethighcontrast", | ||
on: highContrast | ||
} as pxt.editor.EditorMessageSetHighContrastRequest); | ||
}, [highContrast]) | ||
|
||
|
||
useEffect(() => { | ||
if (frameState === "project-open") { | ||
setFrameState("closing-project"); | ||
onFrameClose(); | ||
} | ||
else if (frameState === "no-project") { | ||
setFrameState("opening-project"); | ||
onFrameOpen(); | ||
} | ||
}, [frameState]); | ||
|
||
|
||
const handleFrameReload = () => { | ||
setFrameState("loading") | ||
} | ||
|
||
const onMessageReceived = (event: MessageEvent) => { | ||
const data = event.data as pxt.editor.EditorMessageRequest; | ||
if (frameState === "opening-project") setLoadPercent(Math.min((loadPercent || 0) + 7, 95)); | ||
|
||
if (data.type === "pxteditor" && data.id && pendingMessages[data.id]) { | ||
const pending = pendingMessages[data.id]; | ||
pending.handler(data); | ||
delete pendingMessages[data.id]; | ||
return; | ||
} | ||
|
||
switch (data.action) { | ||
case "newproject": | ||
if (!workspaceReady) { | ||
setWorkspaceReady(true); | ||
sendMessageAsync(); // Flush message queue | ||
} | ||
if (frameState === "loading") { | ||
setFrameState("no-project"); | ||
} | ||
break; | ||
default: | ||
console.log(JSON.stringify(data, null, 4)); | ||
} | ||
} | ||
|
||
const sendMessageAsync = (message?: any) => { | ||
return new Promise(resolve => { | ||
const sendMessageCore = (message: any) => { | ||
message.response = true; | ||
message.id = nextId++ + ""; | ||
pendingMessages[message.id] = { | ||
original: message, | ||
handler: resolve | ||
}; | ||
ref!.contentWindow!.postMessage(message, "*"); | ||
} | ||
( { pageSourceUrl} ) => { | ||
|
||
if (ref) { | ||
if (!workspaceReady) { | ||
messageQueue.push(message); | ||
} | ||
else { | ||
while (messageQueue.length) { | ||
sendMessageCore(messageQueue.shift()); | ||
} | ||
if (message) sendMessageCore(message); | ||
} | ||
} | ||
}); | ||
const handleIFrameRef = (el: HTMLIFrameElement | null) => { | ||
setEditorRef(el ?? undefined); | ||
} | ||
|
||
const openingProject = frameState === "opening-project"; | ||
const showLoader = openingProject || frameState === "closing-project"; | ||
/* eslint-disable @microsoft/sdl/react-iframe-missing-sandbox */ | ||
return <div className="makecode-frame-outer" style={{ display: "block" }}> | ||
<div className={`makecode-frame-loader ${showLoader ? "" : "hidden"}`}> | ||
{openingProject && <ProgressBar className="makecode-frame-loader-bar" value={loadPercent! / 100} />} | ||
<div className="makecode-frame-loader-text">{lf("Loading...")}</div> | ||
</div> | ||
<iframe className="makecode-frame" src={pageSourceUrl} title={"title"} ref={frameRef}></iframe> | ||
<iframe className="makecode-frame" src={pageSourceUrl} title={"title"} ref={handleIFrameRef}></iframe> | ||
</div> | ||
/* eslint-enable @microsoft/sdl/react-iframe-missing-sandbox */ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
interface PendingMessage { | ||
original: pxt.editor.EditorMessageRequest; | ||
handler: (response: any) => void; | ||
} | ||
|
||
let makecodeEditorRef: HTMLIFrameElement | undefined; | ||
const messageQueue: pxt.editor.EditorMessageRequest[] = []; | ||
let nextId: number = 0; | ||
let pendingMessages: {[index: string]: PendingMessage} = {}; | ||
|
||
function onMessageReceived(event: MessageEvent) { | ||
const data = event.data as pxt.editor.EditorMessageRequest; | ||
if (data.type === "pxteditor" && data.id && pendingMessages[data.id]) { | ||
const pending = pendingMessages[data.id]; | ||
pending.handler(data); | ||
delete pendingMessages[data.id]; | ||
return; | ||
} | ||
|
||
console.log("Received message from iframe:", data); | ||
} | ||
|
||
function sendMessageAsync(message?: any) { | ||
return new Promise(resolve => { | ||
const sendMessageCore = (message: any) => { | ||
message.response = true; | ||
message.id = nextId++ + ""; | ||
pendingMessages[message.id] = { | ||
original: message, | ||
handler: resolve | ||
}; | ||
makecodeEditorRef!.contentWindow!.postMessage(message, "*"); | ||
} | ||
|
||
if (message) messageQueue.push(message); | ||
if (makecodeEditorRef) { | ||
while (messageQueue.length) { | ||
sendMessageCore(messageQueue.shift()); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
export function setEditorRef(ref: HTMLIFrameElement | undefined) { | ||
makecodeEditorRef = ref ?? undefined; | ||
window.removeEventListener("message", onMessageReceived); | ||
if (ref) { | ||
window.addEventListener("message", onMessageReceived); | ||
sendMessageAsync(); | ||
} | ||
} | ||
|
||
// an example of events that we want to/can send to the editor | ||
export async function setHighContrastAsync(on: boolean) { | ||
const result = await sendMessageAsync({ | ||
type: "pxteditor", | ||
action: "sethighcontrast", | ||
on: on | ||
}); | ||
console.log(result); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { stateAndDispatch } from "../state"; | ||
import * as Actions from "../state/actions"; | ||
import { postNotification } from "./postNotification"; | ||
import { makeNotification } from "../utils"; | ||
import { setHighContrastAsync } from "../services/makecodeEditorService"; | ||
|
||
export async function loadProjectAsync(projectId: string, bool: boolean) { | ||
const { dispatch } = stateAndDispatch(); | ||
await setHighContrastAsync(bool); | ||
postNotification(makeNotification(`project ${projectId} evaluated`, 2000)); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters