diff --git a/package.json b/package.json index 43b163d..e38eca4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "publisher": "djnicholson", "displayName": "Automatic web panel opener - webpanel.json", "description": "Automatically opens web panels according to the webpanel.json file in the current workspace.", - "version": "1.0.2", + "version": "1.0.3", "icon": "resources/logo.png", "galleryBanner": { "color": "#000000", diff --git a/src/extension/index.ts b/src/extension/index.ts index f79f12b..e938aba 100644 --- a/src/extension/index.ts +++ b/src/extension/index.ts @@ -3,125 +3,142 @@ import * as nodeFetch from "node-fetch"; import * as path from "path"; import * as vscode from "vscode"; +const PATTERN = "**/.vscode/webpanel.json"; + +const FLAG_ACCEPTING_MESSAGES = "accepting-messages"; +const FLAG_PANEL_UP = "panel-up"; + let fileSystemWatcher: vscode.FileSystemWatcher | null = null; let panelsByUrl: { [url: string]: vscode.WebviewPanel } = {}; -let active = false; - let context: vscode.ExtensionContext | null = null; -let loading: { url: string; panel: vscode.WebviewPanel }[] = []; +let urls: { + [url: string]: boolean; +} = {}; function ensurePanel(url: string) { - if (!active || !context) { + if (!context) { return; } const existingPanel = panelsByUrl[url]; - if (!existingPanel || !existingPanel.visible) { - const newPanel = vscode.window.createWebviewPanel( - `web-panel-${url}`, - url, - vscode.ViewColumn.Beside, - { enableScripts: true, retainContextWhenHidden: true } + if (existingPanel) { + return; + } + const newPanel = vscode.window.createWebviewPanel( + `web-panel-${url}`, + url, + vscode.ViewColumn.Two, + { enableScripts: true, retainContextWhenHidden: true } + ); + newPanel.webview.html = fs + .readFileSync( + path.join(context.extensionPath, "dist", "panel", "index.html") + ) + .toString() + .replace( + "[BASE_HREF]", + newPanel.webview + .asWebviewUri( + vscode.Uri.file(path.join(context.extensionPath, "dist", "panel")) + ) + .toString() + "/" ); - newPanel.webview.html = fs - .readFileSync( - path.join(context.extensionPath, "dist", "panel", "index.html") - ) - .toString() - .replace( - "[BASE_HREF]", - newPanel.webview - .asWebviewUri( - vscode.Uri.file(path.join(context.extensionPath, "dist", "panel")) - ) - .toString() + "/" + newPanel.webview.onDidReceiveMessage( + () => ((newPanel as any)[FLAG_ACCEPTING_MESSAGES] = true) + ); + newPanel.onDidDispose(() => delete panelsByUrl[url]); + panelsByUrl[url] = newPanel; +} + +function extractUrls(webPanelJsonFile: vscode.Uri): string[] { + const result: string[] = []; + try { + const fileContents = fs.readFileSync(webPanelJsonFile.fsPath); + const urlList = JSON.parse(fileContents.toString()); + if (!Array.isArray(urlList)) { + vscode.window.showErrorMessage( + "Your webpanel.json file should contain a single array of URLs." ); - newPanel.webview.onDidReceiveMessage( - () => ((newPanel as any)["accepting-messages"] = true) + } else { + result.push(...urlList); + } + } catch (e) { + vscode.window.showErrorMessage( + `Error processing webpanel.json file: ${e.message}` ); - newPanel.onDidDispose(() => delete panelsByUrl[url]); - panelsByUrl[url] = newPanel; - loading.push({ url, panel: newPanel }); } + return result; } -async function loadUrls() { - if (!active) { +async function monitorPanels() { + if (!context) { return; } try { - const toProcess = loading; - loading = []; - for (const _ of toProcess) { - const url = _.url; - const panel = _.panel; - const acceptingMessages = (panel as any)["accepting-messages"]; - if (!acceptingMessages) { - console.log("web-panel", url, "Waiting for panel"); - loading.push(_); - } else { - try { - await nodeFetch.default(url); - try { - panel.webview.postMessage({ url }); - console.log("web-panel", url, "URL up"); - } catch (e) { - console.log("web-panel", url, "Panel error", e.message); + for (const url of Object.getOwnPropertyNames(urls)) { + ensurePanel(url); + const panel = panelsByUrl[url]; + if (panel) { + const acceptingMessages = (panel as any)[FLAG_ACCEPTING_MESSAGES]; + const panelUp = (panel as any)[FLAG_PANEL_UP]; + if (!panelUp) { + if (acceptingMessages) { + try { + await nodeFetch.default(url); + try { + panel.webview.postMessage({ url }); + console.log("web-panel", url, "URL up"); + (panel as any)[FLAG_PANEL_UP] = true; + } catch (e) { + console.log("web-panel", url, "Panel error", e.message); + } + } catch (e) { + console.log("web-panel", url, "Waiting for URL"); + } + } else { + console.log("web-panel", url, "Waiting for panel to initialize"); } - } catch (e) { - console.log("web-panel", url, "Waiting for URL"); - loading.push(_); } + } else { + console.log("web-panel", url, "Waiting for panel to open"); } } } finally { - setTimeout(loadUrls, 1000); + setTimeout(monitorPanels, 1000); } } -function refreshWebPanelJson(file: vscode.Uri) { - if (!active || !context) { - return; - } - try { - const fileContents = fs.readFileSync(file.fsPath); - const urlList = JSON.parse(fileContents.toString()); - if (!Array.isArray(urlList)) { - vscode.window.showErrorMessage( - "Your webpanel.json file should contain a single array of URLs." - ); - } else { - for (const url of urlList) { - ensurePanel(url); +async function parseAllUrls() { + const urlsToRemove = { ...urls }; + const webPanelJsonFiles = await vscode.workspace.findFiles(PATTERN); + for (const webPanelJsonFile of webPanelJsonFiles) { + const urlsThisFile = extractUrls(webPanelJsonFile); + for (const url of urlsThisFile) { + urls[url] = true; + if (!!urlsToRemove[url]) { + delete urlsToRemove[url]; } } - } catch (e) { - vscode.window.showErrorMessage( - `Error processing webpanel.json file: ${e.message}` - ); + } + for (const urlToRemove of Object.getOwnPropertyNames(urlsToRemove)) { + delete urls[urlToRemove]; } } export async function activate(extensionContext: vscode.ExtensionContext) { context = extensionContext; fileSystemWatcher?.dispose(); - fileSystemWatcher = vscode.workspace.createFileSystemWatcher( - "**/.vscode/webpanel.json" - ); - fileSystemWatcher.onDidChange(refreshWebPanelJson); - fileSystemWatcher.onDidCreate(refreshWebPanelJson); - active = true; - const runNow = await vscode.workspace.findFiles("**/.vscode/webpanel.json"); - for (const file of runNow) { - refreshWebPanelJson(file); - } - loadUrls(); + fileSystemWatcher = vscode.workspace.createFileSystemWatcher(PATTERN); + fileSystemWatcher.onDidChange(parseAllUrls); + fileSystemWatcher.onDidCreate(parseAllUrls); + await parseAllUrls(); + await monitorPanels(); } export function deactivate() { - active = false; + context = null; fileSystemWatcher?.dispose(); fileSystemWatcher = null; for (const url of Object.getOwnPropertyNames(panelsByUrl)) { diff --git a/src/panel/Frame.tsx b/src/panel/Frame.tsx index 5ad985c..51e0895 100644 --- a/src/panel/Frame.tsx +++ b/src/panel/Frame.tsx @@ -23,7 +23,7 @@ export default function Frame() { return (
{!!iframeSrc && ( -