mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
Introduce QuickActionsService and QuickAgent for lightweight, single-shot AI operations. Add a dedicated quickActionModel setting alongside a new top-level provider setting, with validation ensuring all models match the selected provider and provider-specific defaults. Refactor FileSystemService to offer both TFile and path-based overloads (readFile/readFilePath, writeToFile/writeToFilePath, patchFile/patchFileAtPath). Replace window/document globals with activeWindow/ activeDocument throughout InputService and VaultkeeperAISettingTab for Obsidian mobile compatibility. Update linting packages to latest.
86 lines
No EOL
2.9 KiB
TypeScript
86 lines
No EOL
2.9 KiB
TypeScript
import type VaultkeeperAIPlugin from "main";
|
|
import { Resolve } from "./DependencyService";
|
|
import { Services } from "./Services";
|
|
import type { WebviewElement } from "Types/WebviewElement";
|
|
|
|
export class WebViewerService {
|
|
|
|
private readonly plugin: VaultkeeperAIPlugin;
|
|
|
|
public constructor() {
|
|
this.plugin = Resolve<VaultkeeperAIPlugin>(Services.VaultkeeperAIPlugin);
|
|
}
|
|
|
|
public async getWebViewContent(urlHint?: string): Promise<string | null> {
|
|
const webviewElement = this.getWebviewElement(urlHint);
|
|
|
|
if (!webviewElement) {
|
|
return null;
|
|
}
|
|
|
|
if (await this.waitForLoad(webviewElement)) {
|
|
const pageContent = await webviewElement.executeJavaScript(
|
|
'document.body.innerText'
|
|
);
|
|
return pageContent as string ?? "Failed to retrieve page content";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
public async takeScreenshot(urlHint?: string, stripDataUrl: boolean = false): Promise<string | null> {
|
|
const webviewElement = this.getWebviewElement(urlHint);
|
|
|
|
if (!webviewElement) {
|
|
return null;
|
|
}
|
|
|
|
if (await this.waitForLoad(webviewElement)) {
|
|
const screenshot = await webviewElement.capturePage();
|
|
const dataUrl = screenshot.toDataURL();
|
|
return stripDataUrl ? dataUrl.split(',')[1] : dataUrl;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private getWebviewElement(urlHint?: string): WebviewElement | null {
|
|
const leaves = this.plugin.app.workspace.getLeavesOfType('webviewer');
|
|
if (leaves.length <= 0) {
|
|
return null;
|
|
}
|
|
|
|
let webviewElement: WebviewElement | null = null;
|
|
if (urlHint) {
|
|
for (const leaf of leaves) {
|
|
const element = leaf.view.containerEl.querySelector('webview');
|
|
if (this.isWebviewElement(element) && element.getURL().contains(urlHint)) {
|
|
webviewElement = element;
|
|
}
|
|
}
|
|
} else {
|
|
const leaf = leaves[0];
|
|
const element = leaf.view.containerEl.querySelector('webview');
|
|
if (this.isWebviewElement(element)) {
|
|
webviewElement = element;
|
|
}
|
|
}
|
|
return webviewElement;
|
|
}
|
|
|
|
private async waitForLoad(webviewElement: WebviewElement, timeoutMs = 10000): Promise<boolean> {
|
|
const start = Date.now();
|
|
while (webviewElement.isLoading()) {
|
|
if (Date.now() - start > timeoutMs) {
|
|
return false;
|
|
}
|
|
await new Promise(r => activeWindow.setTimeout(r, 200));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private isWebviewElement(element: Element | null): element is WebviewElement {
|
|
return element !== null
|
|
&& typeof (element as WebviewElement).isLoading === 'function'
|
|
&& typeof (element as WebviewElement).executeJavaScript === 'function';
|
|
}
|
|
|
|
} |