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);
}
if (blockView === "help") {
return makeHelpViewModel();
return makeHelpViewModel(blockId);
}
return makeDefaultViewModel(blockId, blockView);
}

View File

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

View File

@ -2,26 +2,63 @@
// SPDX-License-Identifier: Apache-2.0
import { getApi } from "@/app/store/global";
import { useState } from "react";
import { WebviewTag } from "electron";
import { createRef, useEffect, useState } from "react";
import "./helpview.less";
class HelpViewModel implements ViewModel {
viewType: string;
blockId: string;
webviewRef: React.RefObject<WebviewTag>;
constructor() {
constructor(blockId: string) {
this.viewType = "help";
this.blockId = blockId;
this.webviewRef = createRef<WebviewTag>();
}
}
function makeHelpViewModel() {
return new HelpViewModel();
function makeHelpViewModel(blockId: string) {
return new HelpViewModel(blockId);
}
function HelpView({}: { model: HelpViewModel }) {
function HelpView({ model }: { model: HelpViewModel }) {
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 (
<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>
);
}

View File

@ -441,69 +441,69 @@ const WebView = memo(({ model }: WebViewProps) => {
useEffect(() => {
const webview = model.webviewRef.current;
if (webview) {
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);
};
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);
};
}, []);
return (

View File

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