Skip to content

fix(mobile): 文件守卫豁免菜单/选择器 UI,模型选择不再被误拦并注入复制按钮 - #149

Open
palxex wants to merge 1 commit into
shaobeichen:mainfrom
palxex:fix/mobile-file-guard-menu-exclusion
Open

palxex wants to merge 1 commit into
shaobeichen:mainfrom
palxex:fix/mobile-file-guard-menu-exclusion

Conversation

@palxex

@palxex palxex commented Oct 1, 2026

Copy link
Copy Markdown

问题

手机(窄屏 / iOS PWA)上打开模型选择器,部分模型无法选中——点击行时误弹「手机上无法直接打开电脑上的文件」,且这些行旁边多出一个「复制」按钮。模型 ID 含 / 和 . 后缀的(如 z-ai/glm-5.3、cl/cline-free/deepseek-v4.1-flash)全部中招;ID 不带后缀的(openai/gpt-4o 等)正常。

根因

issue #17 引入的移动端文件守卫(client/mobile/fileGuard.ts)不依赖类名,靠「文案像不像文件路径」识别文件链接,looksLikeFilePath 的 xxx/xxx.yyy 模式与模型 ID 文本上完全无法区分。而模型选择器(dsh-client-ui-model-selection)的每一行都是 <button role="menuitemradio">,触发按钮带 aria-haspopup="menu",行文案就是模型 ID,于是:

  1. 捕获阶段的 document click 拦截(preventDefault + stopImmediatePropagation)吞掉了模型行的点选,行内的 choose() 永远收不到事件,只弹守卫提示;
  2. injectCopyButtons 的 MutationObserver 给每个「像路径」的按钮旁注入「复制」按钮,模型行也被注入。

修复

文本启发式无法区分二者,改为按 ARIA 上下文豁免:新增 isMenuUi(),元素位于 [role="menu"] / [role="menuitem"] / [role="menuitemradio"] / [role="menuitemcheckbox"] / [role="listbox"] / [role="option"] 内、或自身带 [aria-haspopup="menu"] 时,不算文件链接——点击拦截与复制按钮注入两处都在判路径文案之前先过这一关。

聊天消息里的文件链接不在任何菜单/选择器内,守卫原有行为不变(issue #17 的功能完整保留)。

验证

在真实 DSH Web 实例(窄屏视口、守卫激活状态)实测:

  • 合成元素:role="menuitemradio" + 文案 z-ai/glm-5.3 的按钮点击放行、无复制按钮注入;aria-haspopup="menu" 触发按钮同样放行;对照的真文件链接 lib/proxy.mjs 仍被拦截、弹正确提示、注入复制按钮;
  • 真实模型菜单:钻入模型列表共 101 行,其中 25 个路径形态行,复制按钮注入数 0、误标记 0;
  • 回归:node --test test/file-guard.test.js test/mobile-nav.test.js test/layout-mode.test.js test/locales.test.js 全部通过(29/29,含本次新增断言)。

变更

  • client/mobile/fileGuard.ts:新增 MENU_UI_SELECTOR / isMenuUi(),两处调用点先豁免菜单 UI;
  • client/client.js:node client/build.mjs 重建(esbuild 0.25.9,产物 diff 仅含本次逻辑);
  • test/file-guard.test.js:按仓库既有风格新增结构断言(源码 selector 覆盖 + 两处调用顺序 + 产物含 isMenuUi)。

模型选择器(dsh-client-ui-model-selection)的触发按钮带 aria-haspopup="menu",
各行是 role="menuitemradio"/"menuitem",行文案就是模型 ID。形如
z-ai/glm-5.3、cl/cline-free/deepseek-v4.1-flash 的 ID 会命中
looksLikeFilePath 的 `xxx/xxx.yyy` 模式,在窄屏(手机/PWA)下被误判成
文件链接,于是:
1. 捕获阶段 click 拦截吞掉模型行的点选,误弹「手机上无法直接打开
   电脑上的文件」——路径形态的模型(含 / 和 . 后缀)全部无法选中;
2. MutationObserver 给每个误判的模型行旁注入一个「复制」按钮。

文本上模型 ID 与相对路径(lib/proxy.mjs)无法区分,改为按 ARIA 上下文
豁免:凡位于 [role="menu"]、[role="menuitem"]、[role="menuitemradio"]、
[role="menuitemcheckbox"]、[role="listbox"]、[role="option"] 内,或自身
带 [aria-haspopup="menu"],一律不算文件链接(不拦截、不注入复制按钮)。
聊天消息里的文件链接不在任何菜单内,守卫行为不变。

已在真实环境验证(窄屏视口、守卫激活):模型列表 101 行中 25 个路径形态
行不再被拦、复制按钮注入数为 0;对照文件链接 lib/proxy.mjs 仍被正常
拦截并弹提示、注入复制按钮。

- client/mobile/fileGuard.ts:新增 MENU_UI_SELECTOR/isMenuUi,点击拦截
  与复制按钮注入两处先豁免菜单 UI
- client/client.js:node client/build.mjs 重建(esbuild 0.25.9)
- test/file-guard.test.js:新增菜单豁免断言(源码结构 + 打包产物)
palxex added a commit to palxex/dsh-pocket that referenced this pull request Oct 6, 2026
上游 PR shaobeichen#149(shaobeichen/dsh-pocket)一直没被合并,直接把它的改动带进 fork:

- client/mobile/fileGuard.ts: 菜单/下拉/选项列表 UI(role=menu|menuitem|
  menuitemradio|menuitemcheckbox|listbox|option、aria-haspopup=menu)内的元素
  一律跳过文件守卫,模型选择器不再被误拦、旁边不再被注入「复制」按钮
- test/file-guard.test.js: 对应回归测试
- client/index.jsx / client/pocket-locales.js: 删除设置页「开发者:程序员少北晨 /
  ⭐ 顺手留颗 Star,作者能高兴一整天 / 行,给你一颗 Star」那一栏、zh/en 词典键
  以及指向上游仓库的 Star 链接
- client/client.js: 用 client/build.mjs 重新打包(重打结果与合并结果逐字节一致)
- README.md / README.en.md: 删除同款 Star 文案段
- package.json / package-lock.json: 2.10.6 -> 2.10.7
palxex added a commit to palxex/dsh-pocket that referenced this pull request Oct 6, 2026
合入 upstream PR shaobeichen#149(至今未合并):

- client/mobile/fileGuard.ts: 菜单/下拉/选项列表 UI(role=menu|menuitem|
  menuitemradio|menuitemcheckbox|listbox|option、aria-haspopup=menu)内的元素
  一律跳过文件守卫,模型选择器不再被误拦、旁边不再被注入「复制」按钮
- test/file-guard.test.js: 对应回归测试
- client/client.js: 重新打包
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant