add webcontents id to helpview webview. (#969)

also allow contextmneu items to have sublabel, visible, and enabled
This commit is contained in:
Mike Sawka 2024-10-06 13:55:26 -07:00 committed by GitHub
parent c8ecb3d034
commit f05032bcd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 119 additions and 69 deletions

View File

@ -51,7 +51,7 @@ function makeViewModel(blockId: string, blockView: string, nodeModel: NodeModel)
return makeCpuPlotViewModel(blockId); return makeCpuPlotViewModel(blockId);
} }
if (blockView === "help") { if (blockView === "help") {
return makeHelpViewModel(); return makeHelpViewModel(blockId);
} }
return makeDefaultViewModel(blockId, blockView); return makeDefaultViewModel(blockId, blockView);
} }

View File

@ -24,9 +24,16 @@ class ContextMenuModelType {
role: item.role, role: item.role,
type: item.type, type: item.type,
label: item.label, label: item.label,
sublabel: item.sublabel,
id: crypto.randomUUID(), id: crypto.randomUUID(),
checked: item.checked, checked: item.checked,
}; };
if (item.visible === false) {
electronItem.visible = false;
}
if (item.enabled === false) {
electronItem.enabled = false;
}
if (item.click) { if (item.click) {
this.handlers.set(electronItem.id, item.click); this.handlers.set(electronItem.id, item.click);
} }

View File

@ -2,26 +2,63 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { getApi } from "@/app/store/global"; import { getApi } from "@/app/store/global";
import { useState } from "react"; import { WebviewTag } from "electron";
import { createRef, useEffect, useState } from "react";
import "./helpview.less"; import "./helpview.less";
class HelpViewModel implements ViewModel { class HelpViewModel implements ViewModel {
viewType: string; viewType: string;
blockId: string;
webviewRef: React.RefObject<WebviewTag>;
constructor() { constructor(blockId: string) {
this.viewType = "help"; this.viewType = "help";
this.blockId = blockId;
this.webviewRef = createRef<WebviewTag>();
} }
} }
function makeHelpViewModel() { function makeHelpViewModel(blockId: string) {
return new HelpViewModel(); return new HelpViewModel(blockId);
} }
function HelpView({}: { model: HelpViewModel }) { function HelpView({ model }: { model: HelpViewModel }) {
const [url] = useState(() => getApi().getDocsiteUrl()); const [url] = useState(() => getApi().getDocsiteUrl());
const [webContentsId, setWebContentsId] = useState(null);
const [domReady, setDomReady] = useState(false);
useEffect(() => {
if (model.webviewRef.current && domReady) {
const wcId = model.webviewRef.current.getWebContentsId?.();
if (wcId) {
setWebContentsId(wcId);
}
}
}, [model.webviewRef.current, domReady]);
useEffect(() => {
const webview = model.webviewRef.current;
if (!webview) {
return;
}
const handleDomReady = () => {
setDomReady(true);
};
webview.addEventListener("dom-ready", handleDomReady);
return () => {
webview.removeEventListener("dom-ready", handleDomReady);
};
});
return ( return (
<div className="help-view"> <div className="help-view">
<webview className="docsite-webview" src={url} /> <webview
ref={model.webviewRef}
data-blockid={model.blockId}
data-webcontentsid={webContentsId} // needed for emain
className="docsite-webview"
src={url}
/>
</div> </div>
); );
} }

View File

@ -441,69 +441,69 @@ const WebView = memo(({ model }: WebViewProps) => {
useEffect(() => { useEffect(() => {
const webview = model.webviewRef.current; const webview = model.webviewRef.current;
if (!webview) {
if (webview) { return;
const navigateListener = (e: any) => {
model.handleNavigate(e.url);
};
const newWindowHandler = (e: any) => {
e.preventDefault();
const newUrl = e.detail.url;
console.log("webview new-window event:", newUrl);
fireAndForget(() => openLink(newUrl, true));
};
const startLoadingHandler = () => {
model.setRefreshIcon("xmark-large");
model.setIsLoading(true);
webview.style.backgroundColor = "transparent";
};
const stopLoadingHandler = () => {
model.setRefreshIcon("rotate-right");
model.setIsLoading(false);
setBgColor();
};
const failLoadHandler = (e: any) => {
if (e.errorCode === -3) {
console.warn("Suppressed ERR_ABORTED error", e);
} else {
console.error(`Failed to load ${e.validatedURL}: ${e.errorDescription}`);
}
};
const webviewFocus = () => {
getApi().setWebviewFocus(webview.getWebContentsId());
model.nodeModel.focusNode();
};
const webviewBlur = () => {
getApi().setWebviewFocus(null);
};
const handleDomReady = () => {
setDomReady(true);
setBgColor();
};
webview.addEventListener("did-navigate-in-page", navigateListener);
webview.addEventListener("did-navigate", navigateListener);
webview.addEventListener("did-start-loading", startLoadingHandler);
webview.addEventListener("did-stop-loading", stopLoadingHandler);
webview.addEventListener("new-window", newWindowHandler);
webview.addEventListener("did-fail-load", failLoadHandler);
webview.addEventListener("focus", webviewFocus);
webview.addEventListener("blur", webviewBlur);
webview.addEventListener("dom-ready", handleDomReady);
// Clean up event listeners on component unmount
return () => {
webview.removeEventListener("did-navigate", navigateListener);
webview.removeEventListener("did-navigate-in-page", navigateListener);
webview.removeEventListener("new-window", newWindowHandler);
webview.removeEventListener("did-fail-load", failLoadHandler);
webview.removeEventListener("did-start-loading", startLoadingHandler);
webview.removeEventListener("did-stop-loading", stopLoadingHandler);
webview.removeEventListener("focus", webviewFocus);
webview.removeEventListener("blur", webviewBlur);
webview.removeEventListener("dom-ready", handleDomReady);
};
} }
const navigateListener = (e: any) => {
model.handleNavigate(e.url);
};
const newWindowHandler = (e: any) => {
e.preventDefault();
const newUrl = e.detail.url;
console.log("webview new-window event:", newUrl);
fireAndForget(() => openLink(newUrl, true));
};
const startLoadingHandler = () => {
model.setRefreshIcon("xmark-large");
model.setIsLoading(true);
webview.style.backgroundColor = "transparent";
};
const stopLoadingHandler = () => {
model.setRefreshIcon("rotate-right");
model.setIsLoading(false);
setBgColor();
};
const failLoadHandler = (e: any) => {
if (e.errorCode === -3) {
console.warn("Suppressed ERR_ABORTED error", e);
} else {
console.error(`Failed to load ${e.validatedURL}: ${e.errorDescription}`);
}
};
const webviewFocus = () => {
getApi().setWebviewFocus(webview.getWebContentsId());
model.nodeModel.focusNode();
};
const webviewBlur = () => {
getApi().setWebviewFocus(null);
};
const handleDomReady = () => {
setDomReady(true);
setBgColor();
};
webview.addEventListener("did-navigate-in-page", navigateListener);
webview.addEventListener("did-navigate", navigateListener);
webview.addEventListener("did-start-loading", startLoadingHandler);
webview.addEventListener("did-stop-loading", stopLoadingHandler);
webview.addEventListener("new-window", newWindowHandler);
webview.addEventListener("did-fail-load", failLoadHandler);
webview.addEventListener("focus", webviewFocus);
webview.addEventListener("blur", webviewBlur);
webview.addEventListener("dom-ready", handleDomReady);
// Clean up event listeners on component unmount
return () => {
webview.removeEventListener("did-navigate", navigateListener);
webview.removeEventListener("did-navigate-in-page", navigateListener);
webview.removeEventListener("new-window", newWindowHandler);
webview.removeEventListener("did-fail-load", failLoadHandler);
webview.removeEventListener("did-start-loading", startLoadingHandler);
webview.removeEventListener("did-stop-loading", stopLoadingHandler);
webview.removeEventListener("focus", webviewFocus);
webview.removeEventListener("blur", webviewBlur);
webview.removeEventListener("dom-ready", handleDomReady);
};
}, []); }, []);
return ( return (

View File

@ -86,6 +86,9 @@ declare global {
type?: "separator" | "normal" | "submenu" | "checkbox" | "radio"; type?: "separator" | "normal" | "submenu" | "checkbox" | "radio";
submenu?: ElectronContextMenuItem[]; submenu?: ElectronContextMenuItem[];
checked?: boolean; checked?: boolean;
visible?: boolean;
enabled?: boolean;
sublabel?: string;
}; };
type ContextMenuItem = { type ContextMenuItem = {
@ -95,6 +98,9 @@ declare global {
click?: () => void; // not required if role is set click?: () => void; // not required if role is set
submenu?: ContextMenuItem[]; submenu?: ContextMenuItem[];
checked?: boolean; checked?: boolean;
visible?: boolean;
enabled?: boolean;
sublabel?: string;
}; };
type KeyPressDecl = { type KeyPressDecl = {