feat: 服务化 API 新增 urlTarget 外链认领 + 浏览器 HTTP/HTTPS 二级设置开关
基于 PR #74 的颗粒度讨论向前兼容拓展服务化 API: - TabDescriptor 新增可选 urlTarget(url) 谓词:聊天/界面外链被拦截时按注册 顺序路由到第一个命中的插件 tab 类型(openTab({ type, url, title })), 内置 browser 退居隐式兜底;SIDEBAR_FEATURES 追加 'urlTarget' - 浏览器链接设置改为二级菜单(齿轮弹窗):新增 browserInterceptHttp (默认开)+ browserInterceptHttps(默认关);browserInterceptLinks 保留为总闸(默认开,旧文档零迁移) - 拦截管线:registerLinkInterception 的 takeoverEnabled 改收解析后的 URL,协议/同源纯判定(shouldInterceptLink)签名不变 - 测试:matchUrlTarget(注册顺序/抛错吞掉/browser 永不命中)、jsdom 点击接管门控、parsePrefs 新字段默认值;全默认字面量同步 - 文档:设计文档 + AGENTS.md(字段/示例/设置键)+ README(外链分流)
This commit is contained in:
+26
-7
@@ -12,7 +12,7 @@ import { createElement } from 'react'
|
||||
import { createRoot, type Root } from 'react-dom/client'
|
||||
import type { Context } from '../context-types.ts'
|
||||
import { createSidebarStore } from './state.ts'
|
||||
import { createBetterSidebarService } from './service.ts'
|
||||
import { createBetterSidebarService, matchUrlTarget } from './service.ts'
|
||||
import { resetChunks } from './chunk-loader.ts'
|
||||
import { registerBuiltins } from './builtins/index.ts'
|
||||
import { Sidebar } from './Sidebar.tsx'
|
||||
@@ -153,16 +153,35 @@ export function apply(ctx: Context): void {
|
||||
ctx.effect(
|
||||
() => {
|
||||
try {
|
||||
// External http(s) links in the chat/GUI open the sidebar browser
|
||||
// instead of a new window (gated on the browserInterceptLinks pref
|
||||
// AND the browser tab's enable switch; Ctrl/Cmd+click bypasses).
|
||||
// External http(s) links in the chat/GUI open the sidebar instead
|
||||
// of a new window. Gated on the browserInterceptLinks MASTER pref,
|
||||
// the URL's protocol flag (browserInterceptHttp / Https — https
|
||||
// defaults OFF: most https sites refuse iframe embedding), and the
|
||||
// target tab's enable switch; Ctrl/Cmd+click always bypasses. The
|
||||
// target is the first registered tab whose `urlTarget` claims the
|
||||
// URL (enabled tabs only), else the built-in browser tab.
|
||||
const urlTargetOf = (url: URL): string | undefined => {
|
||||
const prefs = sidebarStore.getPrefs()
|
||||
const enabled = service.getTabs().filter(tab => prefs.tabsEnabled[tab.id] !== false)
|
||||
return matchUrlTarget(enabled, url)?.id
|
||||
}
|
||||
return registerLinkInterception({
|
||||
takeoverEnabled: () => sidebarStore.getPrefs().browserInterceptLinks !== false
|
||||
&& sidebarStore.getPrefs().tabsEnabled['browser'] !== false,
|
||||
takeoverEnabled: (url) => {
|
||||
const prefs = sidebarStore.getPrefs()
|
||||
if (prefs.browserInterceptLinks === false) return false
|
||||
const protocolOn = url.protocol === 'https:'
|
||||
? prefs.browserInterceptHttps !== false
|
||||
: prefs.browserInterceptHttp !== false
|
||||
if (!protocolOn) return false
|
||||
// A plugin claim is the target (already enabled-filtered);
|
||||
// otherwise the built-in browser must be enabled.
|
||||
return urlTargetOf(url) !== undefined || prefs.tabsEnabled['browser'] !== false
|
||||
},
|
||||
openInSidebar: (url) => {
|
||||
let title: string | undefined
|
||||
try { title = new URL(url).hostname } catch { /* keep the default title */ }
|
||||
ctx.betterSidebar?.openTab({ type: 'browser', url, title })
|
||||
const type = urlTargetOf(new URL(url)) ?? 'browser'
|
||||
ctx.betterSidebar?.openTab({ type, url, title })
|
||||
},
|
||||
selfOrigin: window.location.origin,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user