From 64797538c51940d35b4f9257462e55b4697815db Mon Sep 17 00:00:00 2001 From: CyanSalt Date: Thu, 10 Oct 2024 17:33:46 +0800 Subject: [PATCH] feat(browser): add omitbox --- addons/browser/src/renderer/BrowserPane.vue | 132 +++++++++++++++++--- src/api/modules/ui.ts | 2 + src/main/lib/message.ts | 4 +- src/main/lib/window.ts | 6 + src/renderer/components/WebContents.vue | 25 ++-- src/renderer/compositions/web-contents.ts | 91 ++++++++------ 6 files changed, 184 insertions(+), 76 deletions(-) diff --git a/addons/browser/src/renderer/BrowserPane.vue b/addons/browser/src/renderer/BrowserPane.vue index ef639194..609e652c 100644 --- a/addons/browser/src/renderer/BrowserPane.vue +++ b/addons/browser/src/renderer/BrowserPane.vue @@ -1,13 +1,13 @@ diff --git a/src/api/modules/ui.ts b/src/api/modules/ui.ts index 88cd074d..dd24b7a4 100644 --- a/src/api/modules/ui.ts +++ b/src/api/modules/ui.ts @@ -13,6 +13,7 @@ import ObjectEditor from '../../renderer/components/basic/ObjectEditor.vue' import SwitchControl from '../../renderer/components/basic/SwitchControl.vue' import ValueSelector from '../../renderer/components/basic/ValueSelector.vue' import VisualIcon from '../../renderer/components/basic/VisualIcon.vue' +import { RendererWebContentsView } from '../../renderer/compositions/web-contents' import { createContextMenu, openContextMenu, withContextMenuSeparator } from '../../renderer/utils/frame' import { vI18n } from '../../renderer/utils/i18n' import type { RendererAPIContext } from '../types' @@ -58,4 +59,5 @@ export { createContextMenu, withContextMenuSeparator, extractClosestEdge, + RendererWebContentsView, } diff --git a/src/main/lib/message.ts b/src/main/lib/message.ts index 45f626ea..f2f4f492 100644 --- a/src/main/lib/message.ts +++ b/src/main/lib/message.ts @@ -48,7 +48,7 @@ declare module '@commas/electron-ipc' { export interface RendererEvents { 'view-title-updated': (id: number, title: string) => void, 'view-icon-updated': (id: number, icon: string | undefined) => void, - 'view-url-updated': (id: number, url: string) => void, + 'view-url-updated': (id: number, url: string, canGoBack: boolean) => void, 'view-open-url': (url: string) => void, } } @@ -285,7 +285,7 @@ function handleViewEvents(view: WebContentsView, parent: WebContents) { send(parent, 'view-icon-updated', view.webContents.id, icons[icons.length - 1]) }) view.webContents.on('did-start-navigation', (details) => { - send(parent, 'view-url-updated', view.webContents.id, details.url) + send(parent, 'view-url-updated', view.webContents.id, details.url, view.webContents.navigationHistory.canGoBack()) }) } diff --git a/src/main/lib/window.ts b/src/main/lib/window.ts index 2de8e208..60177046 100644 --- a/src/main/lib/window.ts +++ b/src/main/lib/window.ts @@ -20,6 +20,7 @@ declare module '@commas/electron-ipc' { 'destroy-web-contents': (id: number) => void, 'navigate-web-contents': (id: number, url: string) => void, 'resize-web-contents': (id: number, rect: Rectangle) => void, + 'go-to-offset-web-contents': (id: number, offset: number) => void, } } @@ -170,6 +171,11 @@ function handleWindowMessages() { if (!view) return view.setBounds(rect) }) + ipcMain.handle('go-to-offset-web-contents', (event, id, offset) => { + const view = Array.from(webContentsViews).find(item => item.webContents.id === id) + if (!view) return + view.webContents.navigationHistory.goToOffset(offset) + }) } export { diff --git a/src/renderer/components/WebContents.vue b/src/renderer/components/WebContents.vue index 400cf4af..2a1bc93d 100644 --- a/src/renderer/components/WebContents.vue +++ b/src/renderer/components/WebContents.vue @@ -1,36 +1,31 @@ diff --git a/src/renderer/compositions/web-contents.ts b/src/renderer/compositions/web-contents.ts index 9aca7cb9..131c736a 100644 --- a/src/renderer/compositions/web-contents.ts +++ b/src/renderer/compositions/web-contents.ts @@ -1,56 +1,64 @@ import { ipcRenderer } from '@commas/electron-ipc' import { globalHandler } from '../../shared/handler' -export interface RendererWebContentsView { - id: number, - url?: string, - title?: string, - icon?: string, - loading?: boolean, -} - const webContentsViews = $ref([]) export function useWebContentsViews() { return $$(webContentsViews) } -export async function createWebContents(element: HTMLElement) { - const rect = element.getBoundingClientRect() - const id = await ipcRenderer.invoke('create-web-contents', { - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - }) - const view: RendererWebContentsView = { id } - webContentsViews.push(view) - return view -} +export class RendererWebContentsView { + + id: number + url?: string + title?: string + icon?: string + canGoBack?: boolean -export function destroyWebContents(id: number) { - const index = webContentsViews.findIndex(item => item.id === id) - if (index !== -1) { - webContentsViews.splice(index, 1) + constructor(id: number) { + this.id = id } - return ipcRenderer.invoke('destroy-web-contents', id) -} -export function navigateWebContents(id: number, url: string) { - const view = webContentsViews.find(item => item.id === id) - if (view) { - view.url = url + static async create(element: HTMLElement) { + const rect = element.getBoundingClientRect() + const id = await ipcRenderer.invoke('create-web-contents', { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + }) + const view = new RendererWebContentsView(id) + webContentsViews.push(view) + return view + } + + async navigate(url: string) { + if (url === this.url) return + this.url = url + return ipcRenderer.invoke('navigate-web-contents', this.id, url) + } + + resize(element: HTMLElement) { + const rect = element.getBoundingClientRect() + return ipcRenderer.invoke('resize-web-contents', this.id, { + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + }) + } + + goToOffset(offset: number) { + return ipcRenderer.invoke('go-to-offset-web-contents', this.id, offset) + } + + destroy() { + const index = webContentsViews.indexOf(this) + if (index !== -1) { + webContentsViews.splice(index, 1) + } + return ipcRenderer.invoke('destroy-web-contents', this.id) } - return ipcRenderer.invoke('navigate-web-contents', id, url) -} -export function resizeWebContents(id: number, element: HTMLElement) { - const rect = element.getBoundingClientRect() - return ipcRenderer.invoke('resize-web-contents', id, { - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - }) } export function handleWebContentsMessages() { @@ -64,10 +72,11 @@ export function handleWebContentsMessages() { if (!view) return view.icon = icon }) - ipcRenderer.on('view-url-updated', (event, id, url) => { + ipcRenderer.on('view-url-updated', (event, id, url, canGoBack) => { const view = webContentsViews.find(item => item.id === id) if (!view) return view.url = url + view.canGoBack = canGoBack }) ipcRenderer.on('view-open-url', (event, url) => { globalHandler.invoke('global-renderer:open-url', url)