Skip to content

Commit

Permalink
use offline asseteditor.html from mkc cache (#187)
Browse files Browse the repository at this point in the history
* use offline asseteditor.html from mkc cache

* remove console log

* update makecode-core and makecode-browser
  • Loading branch information
riknoll authored Mar 7, 2025
1 parent 73e6e2c commit 533e775
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 107 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@
"dependencies": {
"@types/path-browserify": "^1.0.0",
"@vscode/extension-telemetry": "^0.7.5",
"makecode-browser": "^1.3.1",
"makecode-core": "^1.7.0",
"makecode-browser": "^1.3.2",
"makecode-core": "^1.7.1",
"path-browserify": "^1.0.1"
}
}
9 changes: 9 additions & 0 deletions resources/assetMessaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

window.addEventListener("message", function (m) {
if (m.data._fromVscode) {
if (m.data.type === "fetch-html") {
frame.srcdoc = m.data.srcDoc;
return;
}

frame.contentWindow.postMessage(m.data, "*");

if (m.data.type === "open") {
Expand All @@ -20,5 +25,9 @@
});
document.addEventListener("DOMContentLoaded", function (event) {
frame = document.getElementById("asset-editor-frame");

vscode.postMessage({
type: "fetch-html"
});
});
}())
9 changes: 7 additions & 2 deletions resources/assetframe.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@

<body>
<div id="asset-editor-container">
<iframe id="asset-editor-frame" style="position:absolute;top:0;left:0;width:100%;height:100%;" src="@ASSETURL@" allowfullscreen="allowfullscreen"
sandbox="allow-popups allow-forms allow-scripts allow-same-origin" frameborder="0">
<iframe
id="asset-editor-frame"
style="position:absolute;top:0;left:0;width:100%;height:100%;"
allowfullscreen="allowfullscreen"
sandbox="allow-popups allow-forms allow-scripts allow-same-origin"
frameborder="0"
>
</iframe>
</div>
</body>
Expand Down
26 changes: 19 additions & 7 deletions src/web/assetEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from "vscode";
import { activeWorkspace, findFilesAsync, readFileAsync, writeFileAsync } from "./host";
import { syncJResAsync } from "./jres";
import { readTextFileAsync, throttle } from "./util";
import { getAssetEditorHtmlAsync } from "./makecodeOperations";

let extensionContext: vscode.ExtensionContext;
// const assetUrl = "http://localhost:3232/asseteditor.html";
Expand Down Expand Up @@ -70,6 +71,7 @@ export class AssetEditor {

protected panel: vscode.WebviewPanel;
protected editing: AssetEditorState | undefined;
protected assetEditorHtml: string | undefined;
protected disposables: vscode.Disposable[];
protected pendingMessages: {[index: string]: (res: any) => void} = {};
protected nextId = 0;
Expand Down Expand Up @@ -137,6 +139,12 @@ export class AssetEditor {
}

switch (message.type) {
case "fetch-html":
this.postMessageCore({
type: "fetch-html",
srcDoc: this.assetEditorHtml
});
break;
case "event":
this.handleSimulatorEventAsync(message);
break;
Expand All @@ -158,22 +166,28 @@ export class AssetEditor {
}

sendMessageAsync(message: any) {
message._fromVscode = true;
message.id = this.nextId++;

return new Promise<any>(resolve => {
this.pendingMessages[message.id] = resolve;
this.panel.webview.postMessage(message);
this.postMessageCore(message);
});
}

addDisposable(d: vscode.Disposable) {
this.disposables.push(d);
}

protected postMessageCore(message: any) {
message._fromVscode = true;
this.panel.webview.postMessage(message);
}

protected async initWebviewHtmlAsync() {
this.panel.webview.html = "";
const simulatorHTML = await getAssetEditorHtmlAsync(this.panel.webview);

this.assetEditorHtml = await getAssetEditorHtmlAsync(activeWorkspace());;
const simulatorHTML = await getAssetEditorLoaderHtmlAsync(this.panel.webview);
this.panel.webview.html = simulatorHTML;
}

Expand Down Expand Up @@ -220,16 +234,14 @@ export class AssetEditorSerializer implements vscode.WebviewPanelSerializer {
}


async function getAssetEditorHtmlAsync(webview: vscode.Webview) {
async function getAssetEditorLoaderHtmlAsync(webview: vscode.Webview) {
const uri = vscode.Uri.joinPath(extensionContext.extensionUri, "resources", "assetframe.html");
const contents = await readTextFileAsync(uri);

const pathURL = (s: string) =>
webview.asWebviewUri(vscode.Uri.joinPath(extensionContext.extensionUri, "resources", s)).toString();

return contents
.replace(/@RES@\/([\w\-\.]+)/g, (f, fn) => pathURL(fn))
.replace("@ASSETURL@", assetUrl);
return contents.replace(/@RES@\/([\w\-\.]+)/g, (f, fn) => pathURL(fn));
}

async function readProjectJResAsync() {
Expand Down
119 changes: 59 additions & 60 deletions src/web/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function createVsCodeHost(): Host {
existsAsync: async (p) => existsAsync(rmFolderPrefix(p)),
unlinkAsync: async (p) => unlinkAsync(rmFolderPrefix(p)),
cwdAsync: async () => getFolderName(),
symlinkAsync: async () => {},
symlinkAsync: async () => { },
listFilesAsync: async (d, f) => listFilesAsync(rmFolderPrefix(d), f),
requestAsync: httpRequestCoreAsync,
createLanguageServiceAsync: async (editor) => new BrowserLanguageService(editor),
Expand All @@ -24,7 +24,8 @@ export function createVsCodeHost(): Host {
throw new Error(`Exit with status ${code}`);
},
bufferToString: buffer => new TextDecoder().decode(buffer),
stringToBuffer
stringToBuffer,
base64EncodeBufferAsync
};
}

Expand Down Expand Up @@ -104,78 +105,65 @@ async function listFilesAsync(directory: string, filename: string) {
});
}

export function httpRequestCoreAsync(options: HttpRequestOptions) {
return new Promise<HttpResponse>((resolve, reject) => {
let client: XMLHttpRequest;
let resolved = false;
export async function httpRequestCoreAsync(options: HttpRequestOptions) {
const headers = options.headers || {};
const data = options.data;
const method = options.method || (data == null ? "GET" : "POST");

let buf: null | Uint8Array | string;

if (data == null) {
buf = null;
} else if (data instanceof Uint8Array) {
buf = data;
} else if (typeof data === "object") {
buf = JSON.stringify(data);
headers["content-type"] = "application/json; charset=utf8";
} else if (typeof data === "string") {
buf = data;
} else {
throw new Error("bad data");
}

let headers = options.headers || {};
const requestHeaders = new Headers();
Object.keys(headers).forEach(k => {
requestHeaders.set(k, headers[k]);
});

client = new XMLHttpRequest();
client.onreadystatechange = () => {
if (resolved) {return;} // Safari/iOS likes to call this thing more than once
const resp = await fetch(options.url, {
method,
headers: requestHeaders,
body: buf
});

if (client.readyState === 4) {
resolved = true;
let res: HttpResponse = {
statusCode: client.status,
headers: {},
buffer: (client as any).responseBody || client.response,
text: client.responseText,
};
const body = await resp.arrayBuffer();

if (typeof res.buffer === "string") {
res.buffer = new TextEncoder().encode(res.buffer);
}
const allHeaders = client.getAllResponseHeaders();
allHeaders.split(/\r?\n/).forEach(l => {
let m = /^\s*([^:]+): (.*)/.exec(l);
if (m) {
res.headers[m[1].toLowerCase()] = m[2];
}
});
resolve(res);
}
};
let text: string | undefined;

let data = options.data;
let method = options.method || (data == null ? "GET" : "POST");

let buf: any;

if (data == null) {
buf = null;
} else if (data instanceof Uint8Array) {
buf = data;
} else if (typeof data === "object") {
buf = JSON.stringify(data);
headers["content-type"] = "application/json; charset=utf8";
} else if (typeof data === "string") {
buf = data;
} else {
throw new Error("bad data");
}
try {
text = new TextDecoder().decode(body);
}
catch (e) {
// binary data
}

client.open(method, options.url);
const res: HttpResponse = {
statusCode: resp.status,
headers: {},
buffer: new Uint8Array(body),
text,
};

Object.keys(headers).forEach(k => {
client.setRequestHeader(k, headers[k]);
});
resp.headers.forEach((value, key) => res.headers[key.toLowerCase()] = value);

if (buf == null) {
client.send();
}
else {
client.send(buf);
}
});
return res;
}

function resolvePath(path: string) {
return vscode.Uri.joinPath(activeWorkspace().uri, path);
}

export function stringToBuffer(str: string, encoding?: string){
export function stringToBuffer(str: string, encoding?: string) {
let contents: string;
if (encoding === "base64") {
try {
Expand Down Expand Up @@ -237,4 +225,15 @@ export async function findFilesAsync(extension: string, root: vscode.Uri, matchW
}

return result;
}

function base64EncodeBufferAsync(buffer: Uint8Array | ArrayBuffer): Promise<string> {
return new Promise<string>(resolve => {
const reader = new FileReader();
reader.onload = () => {
const url = reader.result as string;
resolve(url.slice(url.indexOf(',') + 1));
};
reader.readAsDataURL(new Blob([buffer]));
});
}
4 changes: 4 additions & 0 deletions src/web/makecodeOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export function getSimHtmlAsync(folder: vscode.WorkspaceFolder, cancellationToke
return enqueueOperationAsync(folder, () => cmd.getSimHTML({}), cancellationToken);
}

export function getAssetEditorHtmlAsync(folder: vscode.WorkspaceFolder, cancellationToken?: vscode.CancellationToken) {
return enqueueOperationAsync(folder, () => cmd.getAssetEditorHTML({}), cancellationToken);
}

/**
* The mkc CLI uses global state, so we need to perform operations in a queue just in case the
* user is doing things in multiple workspaces at once
Expand Down
Loading

0 comments on commit 533e775

Please sign in to comment.