minecodex 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/features/hide-upsell-banner/README.md +2 -1
- package/features/hide-upsell-banner/src/hide-upsell-banner.mjs +9 -10
- package/features/images/README.md +1 -0
- package/features/images/codex-feature.json +1 -1
- package/features/images/web/app.js +30 -0
- package/features/images/web/index.html +5 -0
- package/features/images/web/styles.css +9 -0
- package/package.json +1 -1
- package/packages/runtime-host/src/codex-runtime.mjs +319 -51
- package/packages/runtime-host/src/feature-registry.mjs +1 -0
|
@@ -9,6 +9,7 @@ Toolbar 入口,由 `CodexRuntimeHost` 在渲染进程内注入一段脚本。
|
|
|
9
9
|
功能范围:
|
|
10
10
|
|
|
11
11
|
- 仅隐藏横幅的 GUI 显示(`aside` 卡片,`display: none`);
|
|
12
|
+
- 只以 `aside` 和中英文额度耗尽标题识别,不依赖易变的卡片 class、升级、购买 Credit 或使用重置文案;
|
|
12
13
|
- 不拦截、不篡改额度查询接口(`account/rateLimits/read` 与 app-server
|
|
13
14
|
JSON-RPC 流量保持原样);
|
|
14
15
|
- 横幅重新渲染时由 `MutationObserver` 持续处理,不会闪烁后残留;
|
|
@@ -23,5 +24,5 @@ npm test
|
|
|
23
24
|
## 适配说明
|
|
24
25
|
|
|
25
26
|
这是非官方 CDP / DOM Adapter 的功能声明。Codex 私有 DOM 的适配实现统一留在
|
|
26
|
-
`CodexRuntimeHost
|
|
27
|
+
`CodexRuntimeHost`;本功能只声明横幅的识别规则(`aside` + 耗尽标题)与
|
|
27
28
|
隐藏动作。
|
|
@@ -13,16 +13,15 @@ function isUpsellBanner(element) {
|
|
|
13
13
|
if (!(element instanceof window.HTMLElement)) return false;
|
|
14
14
|
const text = (element.innerText ?? "").trim();
|
|
15
15
|
if (!text) return false;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|| /
|
|
23
|
-
|| /Codex
|
|
24
|
-
|
|
25
|
-
return titleMatch && actionMatch;
|
|
16
|
+
const title = (
|
|
17
|
+
element.querySelector("h1, h2, h3, [role='heading']")?.innerText
|
|
18
|
+
?? text.split("\n", 1)[0]
|
|
19
|
+
).trim();
|
|
20
|
+
return /out of Codex(?: and Work)? usage/i.test(title)
|
|
21
|
+
|| /out of Codex messages/i.test(title)
|
|
22
|
+
|| /Codex (?:message )?usage limit reached/i.test(title)
|
|
23
|
+
|| /Codex.*(?:用量|使用量|使用额度|额度|消息).*(?:用完|用尽|耗尽|已达|达到.*上限|上限)/i.test(title)
|
|
24
|
+
|| /(?:已达到|达到|已用完|已用尽|耗尽).{0,20}Codex.{0,20}(?:用量|使用量|额度|消息|上限)/i.test(title);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
function hideBanner(element) {
|
|
@@ -79,6 +79,7 @@ HTTP + Images UI
|
|
|
79
79
|
- 支持 Codex 的明亮 / 暗黑主题,并监听根节点 theme class 与 style 变化。
|
|
80
80
|
- 用户修改 accent、ink 或 surface 后,新的 resolved tokens 会同步到 iframe,不需要重新读取或猜测内部配置文件位置。
|
|
81
81
|
- 侧边栏 Images 入口克隆原生 Plugins 控件的布局与状态,再替换为 Codex 图标体系中的独立 Image 图标;iframe 内不导入 Codex 私有 React 模块或 hashed CSS bundle,以免 Codex 更新后直接失效。
|
|
82
|
+
- 原生左侧栏隐藏时,Images 标题左侧显示同源图标入口;点击由 RuntimeHost 转发给原生侧栏开关,恢复后入口自动隐藏。
|
|
82
83
|
|
|
83
84
|
取证、token Interface 和代码复用边界见 [`docs/CODEX_DESIGN_LANGUAGE.md`](docs/CODEX_DESIGN_LANGUAGE.md)。
|
|
84
85
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"pageScript": {
|
|
17
17
|
"resource": "src/chatgpt-image-source-page.mjs"
|
|
18
18
|
},
|
|
19
|
-
"hostActions": ["import-generated-image", "create-image-edit-thread"],
|
|
19
|
+
"hostActions": ["import-generated-image", "create-image-edit-thread", "open-sidebar"],
|
|
20
20
|
"placement": {
|
|
21
21
|
"after": "sites",
|
|
22
22
|
"order": 10
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const shell = document.querySelector(".library-shell");
|
|
2
|
+
const libraryHeader = document.querySelector(".library-header");
|
|
3
|
+
const sidebarOpenButton = document.querySelector(".sidebar-open-button");
|
|
2
4
|
const scrollArea = document.querySelector(".library-scroll");
|
|
3
5
|
const grid = document.querySelector(".image-grid");
|
|
4
6
|
const pageSentinel = document.querySelector(".page-sentinel");
|
|
@@ -141,9 +143,26 @@ function announce(message) {
|
|
|
141
143
|
});
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
function applySidebarState(payload) {
|
|
147
|
+
const available = Boolean(payload?.available);
|
|
148
|
+
const open = Boolean(payload?.open);
|
|
149
|
+
const label = typeof payload?.label === "string" && payload.label.trim()
|
|
150
|
+
? payload.label.trim()
|
|
151
|
+
: "Show sidebar";
|
|
152
|
+
const visible = available && !open;
|
|
153
|
+
const leading = Number(payload?.leading);
|
|
154
|
+
sidebarOpenButton.hidden = !visible;
|
|
155
|
+
sidebarOpenButton.setAttribute("aria-label", label);
|
|
156
|
+
sidebarOpenButton.title = label;
|
|
157
|
+
libraryHeader.style.paddingLeft = visible && Number.isFinite(leading)
|
|
158
|
+
? `${Math.max(8, leading)}px`
|
|
159
|
+
: "";
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
window.addEventListener("message", (event) => {
|
|
145
163
|
if (event.source !== window.parent) return;
|
|
146
164
|
if (event.data?.type === "codex-personal:theme") applyHostTheme(event.data);
|
|
165
|
+
if (event.data?.type === "codex-personal:sidebar-state") applySidebarState(event.data);
|
|
147
166
|
if (["codex-personal:surface-active", "codex-personal:surface-visibility"].includes(event.data?.type)) {
|
|
148
167
|
setHostSurfaceActive(event.data.active ?? event.data.visible);
|
|
149
168
|
}
|
|
@@ -974,6 +993,17 @@ densitySlider.addEventListener("input", () => {
|
|
|
974
993
|
});
|
|
975
994
|
|
|
976
995
|
groupButton.addEventListener("click", () => toggleThreadGrouping().catch(console.error));
|
|
996
|
+
sidebarOpenButton.addEventListener("click", async () => {
|
|
997
|
+
sidebarOpenButton.disabled = true;
|
|
998
|
+
try {
|
|
999
|
+
await requestHostAction("open-sidebar", {});
|
|
1000
|
+
applySidebarState({ available: true, open: true, label: sidebarOpenButton.title });
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
announce(error.message);
|
|
1003
|
+
} finally {
|
|
1004
|
+
sidebarOpenButton.disabled = false;
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
977
1007
|
|
|
978
1008
|
document.addEventListener("click", (event) => {
|
|
979
1009
|
if (!event.target.closest(".source-filter")) closeToolbarPopups();
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
<section class="library-pane">
|
|
12
12
|
<header class="library-header">
|
|
13
13
|
<div class="identity">
|
|
14
|
+
<button class="icon-button sidebar-open-button" type="button" aria-label="Show sidebar" title="Show sidebar" hidden>
|
|
15
|
+
<svg class="sidebar-toggle-icon" viewBox="0 0 20 20" aria-hidden="true">
|
|
16
|
+
<path d="M6.83496 3.99992C6.38353 4.00411 6.01421 4.0122 5.69824 4.03801C5.31232 4.06954 5.03904 4.12266 4.82227 4.20012L4.62207 4.28606C4.18264 4.50996 3.81498 4.85035 3.55859 5.26848L3.45605 5.45207C3.33013 5.69922 3.25006 6.01354 3.20801 6.52824C3.16533 7.05065 3.16504 7.71885 3.16504 8.66301V11.3271C3.16504 12.2712 3.16533 12.9394 3.20801 13.4618C3.25006 13.9766 3.33013 14.2909 3.45605 14.538L3.55859 14.7216C3.81498 15.1397 4.18266 15.4801 4.62207 15.704L4.82227 15.79C5.03904 15.8674 5.31234 15.9205 5.69824 15.9521C6.01398 15.9779 6.383 15.986 6.83398 15.9902L6.83496 3.99992ZM18.165 11.3271C18.165 12.2493 18.1653 12.9811 18.1172 13.5702C18.0745 14.0924 17.9916 14.5472 17.8125 14.9648L17.7295 15.1415C17.394 15.8 16.8834 16.3511 16.2568 16.7353L15.9814 16.8896C15.5157 17.1268 15.0069 17.2285 14.4102 17.2773C13.821 17.3254 13.0893 17.3251 12.167 17.3251H7.83301C6.91071 17.3251 6.17898 17.3254 5.58984 17.2773C5.06757 17.2346 4.61294 17.1508 4.19531 16.9716L4.01855 16.8896C3.36014 16.5541 2.80898 16.0434 2.4248 15.4169L2.27051 15.1415C2.03328 14.6758 1.93158 14.167 1.88281 13.5702C1.83468 12.9811 1.83496 12.2493 1.83496 11.3271V8.66301C1.83496 7.74072 1.83468 7.00898 1.88281 6.41985C1.93157 5.82309 2.03329 5.31432 2.27051 4.84856L2.4248 4.57317C2.80898 3.94666 3.36012 3.436 4.01855 3.10051L4.19531 3.0175C4.61285 2.83843 5.06771 2.75548 5.58984 2.71281C6.17898 2.66468 6.91071 2.66496 7.83301 2.66496H12.167C13.0893 2.66496 13.821 2.66468 14.4102 2.71281C15.0069 2.76157 15.5157 2.86329 15.9814 3.10051L16.2568 3.25481C16.8833 3.63898 17.394 4.19012 17.7295 4.84856L17.8125 5.02531C17.9916 5.44285 18.0745 5.89771 18.1172 6.41985C18.1653 7.00898 18.165 7.74072 18.165 8.66301V11.3271ZM8.16406 15.995H12.167C13.1112 15.995 13.7794 15.9947 14.3018 15.9521C14.8164 15.91 15.1308 15.8299 15.3779 15.704L15.5615 15.6015C15.9797 15.3451 16.32 14.9774 16.5439 14.538L16.6299 14.3378C16.7074 14.121 16.7605 13.8478 16.792 13.4618C16.8347 12.9394 16.835 12.2712 16.835 11.3271V8.66301C16.835 7.71885 16.8347 7.05065 16.792 6.52824C16.7605 6.14232 16.7073 5.86904 16.6299 5.65227L16.5439 5.45207C16.32 5.01264 15.9796 4.64498 15.5615 4.3886L15.3779 4.28606C15.1308 4.16013 14.8165 4.08006 14.3018 4.03801C13.7794 3.99533 13.1112 3.99504 12.167 3.99504H8.16406C8.16407 3.99667 8.16504 3.99829 8.16504 3.99992L8.16406 15.995Z"></path>
|
|
17
|
+
</svg>
|
|
18
|
+
</button>
|
|
14
19
|
<h1>Images</h1>
|
|
15
20
|
</div>
|
|
16
21
|
<button class="icon-button rescan-button" type="button" aria-label="Refresh images" title="Refresh images">
|
|
@@ -240,6 +240,15 @@ button { color: inherit; }
|
|
|
240
240
|
gap: 7px;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
.sidebar-open-button { flex: 0 0 auto; }
|
|
244
|
+
.sidebar-open-button[hidden] { display: none; }
|
|
245
|
+
|
|
246
|
+
.sidebar-toggle-icon {
|
|
247
|
+
width: 16px;
|
|
248
|
+
height: 16px;
|
|
249
|
+
fill: currentColor;
|
|
250
|
+
}
|
|
251
|
+
|
|
243
252
|
h1,
|
|
244
253
|
h2,
|
|
245
254
|
h3,
|
package/package.json
CHANGED
|
@@ -144,6 +144,13 @@ export function createInjectionSource(features, {
|
|
|
144
144
|
scheduled: ["scheduled", "计划任务"],
|
|
145
145
|
plugins: ["plugins", "插件"],
|
|
146
146
|
};
|
|
147
|
+
const nativeToolbarLabels = {
|
|
148
|
+
summary: ["Toggle summary", "切换摘要"],
|
|
149
|
+
pinnedSummary: ["Toggle pinned summary", "切换固定摘要"],
|
|
150
|
+
bottomPanel: ["Toggle bottom panel", "切换底部面板"],
|
|
151
|
+
sidePanel: ["Toggle side panel", "切换侧边面板"],
|
|
152
|
+
temporaryChat: ["temporary chat", "临时聊天", "临时对话"],
|
|
153
|
+
};
|
|
147
154
|
const themeTokenNames = [
|
|
148
155
|
"--codex-base-accent",
|
|
149
156
|
"--codex-base-ink",
|
|
@@ -170,6 +177,7 @@ export function createInjectionSource(features, {
|
|
|
170
177
|
"--color-background-elevated-primary-opaque",
|
|
171
178
|
"--color-background-primary-ghost-hover",
|
|
172
179
|
"--color-chart-blue",
|
|
180
|
+
"--color-chart-purple",
|
|
173
181
|
"--color-background-panel",
|
|
174
182
|
"--color-background-control",
|
|
175
183
|
"--color-background-primary-solid",
|
|
@@ -303,6 +311,7 @@ export function createInjectionSource(features, {
|
|
|
303
311
|
const modelSelectorOriginalItems = new Map();
|
|
304
312
|
const modelSelectorOriginalToggleLabels = new Map();
|
|
305
313
|
const modelSelectorGenericContainers = new Map();
|
|
314
|
+
const modelSelectorNativeToggleHandlers = new Map();
|
|
306
315
|
const modelSelectorPositionObservers = new Map();
|
|
307
316
|
const modelSelectorMenuSizeFrames = new Map();
|
|
308
317
|
let modelSelectorReturnTimer = null;
|
|
@@ -327,9 +336,11 @@ export function createInjectionSource(features, {
|
|
|
327
336
|
[data-codex-model-slider-menu] { width: 264px !important; min-width: 264px; overflow-x: hidden; }
|
|
328
337
|
[data-codex-model-slider-controller-menu] {
|
|
329
338
|
position: absolute !important;
|
|
330
|
-
|
|
339
|
+
left: 50%;
|
|
331
340
|
bottom: 0;
|
|
341
|
+
transform: translateX(-50%) !important;
|
|
332
342
|
z-index: 10;
|
|
343
|
+
padding: 6px;
|
|
333
344
|
background-color: var(--color-surface-elevated-secondary);
|
|
334
345
|
-webkit-backdrop-filter: none;
|
|
335
346
|
backdrop-filter: none;
|
|
@@ -339,10 +350,10 @@ export function createInjectionSource(features, {
|
|
|
339
350
|
overflow-y: auto;
|
|
340
351
|
}
|
|
341
352
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerModelLabel_"] {
|
|
342
|
-
max-width:
|
|
353
|
+
min-width: 0; max-width: 110px; flex-shrink: 1; overflow: hidden; text-overflow: ellipsis;
|
|
343
354
|
}
|
|
344
355
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerModelText_"] {
|
|
345
|
-
overflow:
|
|
356
|
+
min-width: 0; max-width: 110px; overflow: hidden; text-overflow: ellipsis;
|
|
346
357
|
}
|
|
347
358
|
html[data-codex-model-slider-catalog-ready]
|
|
348
359
|
[data-codex-intelligence-trigger]
|
|
@@ -350,11 +361,37 @@ export function createInjectionSource(features, {
|
|
|
350
361
|
display: none !important;
|
|
351
362
|
}
|
|
352
363
|
[data-codex-model-slider-trigger-label] {
|
|
353
|
-
display: inline;
|
|
364
|
+
display: inline-block; min-width: 0; max-width: 110px;
|
|
365
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
366
|
+
}
|
|
367
|
+
/* 展示真实模型名/思考强度时:芯片 HUG 内容,长名称不被截断;
|
|
368
|
+
仅 "Select model / Select effort" 占位态沿用原生宽度。 */
|
|
369
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [data-codex-model-slider-trigger-label] {
|
|
370
|
+
max-width: none; overflow: visible; text-overflow: clip; flex-shrink: 0;
|
|
371
|
+
}
|
|
372
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="_ModelPickerTriggerModelLabel_"] {
|
|
373
|
+
max-width: none; overflow: visible; flex-shrink: 0;
|
|
374
|
+
}
|
|
375
|
+
[data-codex-model-slider-trigger]:not([data-codex-model-slider-trigger-placeholder]) [class*="_ModelPickerTriggerContent_"] {
|
|
376
|
+
max-width: none !important;
|
|
377
|
+
}
|
|
378
|
+
[data-codex-model-slider-trigger][data-codex-model-slider-trigger-placeholder] [class*="_ModelPickerTriggerContent_"] {
|
|
379
|
+
width: 160px; min-width: 160px !important; max-width: 160px;
|
|
354
380
|
}
|
|
355
381
|
[data-codex-model-slider-trigger] [class*="_ModelPickerTriggerEffortLabel_"] {
|
|
356
382
|
display: inline-flex; align-items: center; align-self: center;
|
|
357
383
|
}
|
|
384
|
+
/* 无 Fast 模式时,模型按钮 wrapper 居中,不再按有 Fast 的左对齐策略排布。 */
|
|
385
|
+
[data-codex-model-slider-has-fast="false"] [data-codex-model-slider-model-button] {
|
|
386
|
+
box-sizing: border-box; width: 100%; max-width: 100%; margin-inline: auto;
|
|
387
|
+
flex: 0 1 100%; justify-content: center;
|
|
388
|
+
}
|
|
389
|
+
[data-codex-model-slider-has-fast="false"] [data-codex-model-slider-model-button] > span {
|
|
390
|
+
width: 100%; min-width: 0;
|
|
391
|
+
}
|
|
392
|
+
[data-codex-model-slider-has-fast="false"] > :has(> [data-codex-model-slider-model-button])::before {
|
|
393
|
+
display: none !important; content: none !important;
|
|
394
|
+
}
|
|
358
395
|
html[data-codex-model-slider-selecting-effort] [role="menu"][data-state="open"]:not(:has([data-reasoning-slider])) {
|
|
359
396
|
visibility: hidden !important; opacity: 0 !important; animation: none !important; pointer-events: none !important;
|
|
360
397
|
}
|
|
@@ -364,6 +401,10 @@ export function createInjectionSource(features, {
|
|
|
364
401
|
[data-codex-model-slider-copy] { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 1px; }
|
|
365
402
|
[data-codex-model-slider-name] { overflow: hidden; color: var(--color-text-foreground); text-overflow: ellipsis; white-space: nowrap; }
|
|
366
403
|
[data-codex-model-slider-provider] { overflow: hidden; color: var(--color-text-foreground-tertiary); font-size: 11px; line-height: 14px; text-overflow: ellipsis; white-space: nowrap; }
|
|
404
|
+
[data-codex-model-slider-model-label] {
|
|
405
|
+
display: -webkit-box; min-width: 0; overflow: hidden; overflow-wrap: anywhere;
|
|
406
|
+
-webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal;
|
|
407
|
+
}
|
|
367
408
|
[data-codex-model-slider-item] { position: relative; }
|
|
368
409
|
[data-codex-model-slider-item][data-codex-model-slider-selected] { background: var(--color-token-list-hover-background); }
|
|
369
410
|
[data-codex-model-slider-star] {
|
|
@@ -380,8 +421,14 @@ export function createInjectionSource(features, {
|
|
|
380
421
|
content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 40px; z-index: 1;
|
|
381
422
|
}
|
|
382
423
|
[data-codex-model-slider-star] svg { position: relative; z-index: 2; width: 16px; height: 16px; pointer-events: none; }
|
|
383
|
-
[data-codex-model-slider-divider] {
|
|
384
|
-
|
|
424
|
+
[data-codex-model-slider-divider] {
|
|
425
|
+
height: 0; border-top: 1px solid var(--color-token-border, var(--color-border));
|
|
426
|
+
margin: 6px 8px;
|
|
427
|
+
}
|
|
428
|
+
[data-codex-model-slider-generic-menu] {
|
|
429
|
+
overflow-x: hidden;
|
|
430
|
+
transform: translateX(var(--codex-model-slider-menu-center-shift, 0px)) !important;
|
|
431
|
+
}
|
|
385
432
|
[data-codex-model-slider-generic] { box-sizing: border-box; width: 100%; }
|
|
386
433
|
[data-codex-model-slider-fast] { margin-left: auto; border: 0; background: transparent; cursor: pointer; }
|
|
387
434
|
[data-codex-model-slider-fast]:focus-visible { outline: 2px solid var(--color-border-focus); outline-offset: 1px; }
|
|
@@ -473,11 +520,20 @@ export function createInjectionSource(features, {
|
|
|
473
520
|
&& rect.height > 0;
|
|
474
521
|
}
|
|
475
522
|
|
|
523
|
+
function hasNativeToolbarLabel(button, key) {
|
|
524
|
+
const label = String(button?.getAttribute("aria-label") ?? "").trim().toLowerCase();
|
|
525
|
+
return nativeToolbarLabels[key].some((candidate) => (
|
|
526
|
+
key === "temporaryChat"
|
|
527
|
+
? label.includes(candidate.toLowerCase())
|
|
528
|
+
: label === candidate.toLowerCase()
|
|
529
|
+
));
|
|
530
|
+
}
|
|
531
|
+
|
|
476
532
|
function nativeSummaryButton() {
|
|
477
533
|
return Array.from(document.querySelectorAll("button")).find((button) => (
|
|
478
534
|
(
|
|
479
|
-
button
|
|
480
|
-
|| button
|
|
535
|
+
hasNativeToolbarLabel(button, "summary")
|
|
536
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary")
|
|
481
537
|
)
|
|
482
538
|
&& isVisibleToolbarControl(button)
|
|
483
539
|
)) ?? null;
|
|
@@ -485,32 +541,34 @@ export function createInjectionSource(features, {
|
|
|
485
541
|
|
|
486
542
|
function nativeBottomPanelButton() {
|
|
487
543
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
488
|
-
if (button
|
|
544
|
+
if (!hasNativeToolbarLabel(button, "bottomPanel")) return false;
|
|
489
545
|
return isVisibleToolbarControl(button);
|
|
490
546
|
}) ?? null;
|
|
491
547
|
}
|
|
492
548
|
|
|
493
549
|
function nativeSidePanelButton() {
|
|
494
550
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
495
|
-
if (button
|
|
551
|
+
if (!hasNativeToolbarLabel(button, "sidePanel")) return false;
|
|
496
552
|
return isVisibleToolbarControl(button);
|
|
497
553
|
}) ?? null;
|
|
498
554
|
}
|
|
499
555
|
|
|
500
556
|
function nativeTemporaryChatButton() {
|
|
501
557
|
return Array.from(document.querySelectorAll("button")).find((button) => {
|
|
502
|
-
if (
|
|
558
|
+
if (!hasNativeToolbarLabel(button, "temporaryChat")) return false;
|
|
503
559
|
return isVisibleToolbarControl(button);
|
|
504
560
|
}) ?? null;
|
|
505
561
|
}
|
|
506
562
|
|
|
507
563
|
function structuralToolbarAnchor() {
|
|
508
564
|
const buttons = Array.from(document.querySelectorAll("button"));
|
|
509
|
-
return buttons.find((button) =>
|
|
510
|
-
?? buttons.find((button) =>
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
565
|
+
return buttons.find((button) => hasNativeToolbarLabel(button, "temporaryChat"))
|
|
566
|
+
?? buttons.find((button) => (
|
|
567
|
+
hasNativeToolbarLabel(button, "summary")
|
|
568
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary")
|
|
569
|
+
))
|
|
570
|
+
?? buttons.find((button) => hasNativeToolbarLabel(button, "bottomPanel"))
|
|
571
|
+
?? buttons.find((button) => hasNativeToolbarLabel(button, "sidePanel"))
|
|
514
572
|
?? null;
|
|
515
573
|
}
|
|
516
574
|
|
|
@@ -604,8 +662,8 @@ export function createInjectionSource(features, {
|
|
|
604
662
|
function isNativeSummaryButton(element) {
|
|
605
663
|
if (!(element instanceof Element)) return false;
|
|
606
664
|
const button = element.closest("button");
|
|
607
|
-
return button
|
|
608
|
-
|| button
|
|
665
|
+
return hasNativeToolbarLabel(button, "summary")
|
|
666
|
+
|| hasNativeToolbarLabel(button, "pinnedSummary");
|
|
609
667
|
}
|
|
610
668
|
|
|
611
669
|
function mainContentViewport() {
|
|
@@ -954,6 +1012,11 @@ export function createInjectionSource(features, {
|
|
|
954
1012
|
return formatIdentifier(source.slice(source.lastIndexOf("/") + 1));
|
|
955
1013
|
}
|
|
956
1014
|
|
|
1015
|
+
function compactModelLabel(rawValue) {
|
|
1016
|
+
const raw = String(rawValue ?? "").trim();
|
|
1017
|
+
return formatIdentifier(raw.slice(raw.lastIndexOf("/") + 1));
|
|
1018
|
+
}
|
|
1019
|
+
|
|
957
1020
|
function brandForModel(identity, selector) {
|
|
958
1021
|
const haystack = `${identity.backend} ${identity.raw}`.toLowerCase();
|
|
959
1022
|
return selector.brands?.find((brand) => (
|
|
@@ -1152,7 +1215,10 @@ export function createInjectionSource(features, {
|
|
|
1152
1215
|
|
|
1153
1216
|
function nativeModelPickerMenu() {
|
|
1154
1217
|
return Array.from(document.querySelectorAll('[role="menu"][data-state="open"]')).find(
|
|
1155
|
-
(menu) =>
|
|
1218
|
+
(menu) => (
|
|
1219
|
+
menu.querySelector("[data-reasoning-slider]")
|
|
1220
|
+
&& (menu.querySelector("[data-model-picker-view-toggle]") || nativeModelPickerRow(menu))
|
|
1221
|
+
),
|
|
1156
1222
|
) ?? null;
|
|
1157
1223
|
}
|
|
1158
1224
|
|
|
@@ -1169,6 +1235,14 @@ export function createInjectionSource(features, {
|
|
|
1169
1235
|
}
|
|
1170
1236
|
|
|
1171
1237
|
function nativeModelValue(menu) {
|
|
1238
|
+
const toggle = menu?.querySelector("[data-model-picker-view-toggle]");
|
|
1239
|
+
const toggleModelLabel = toggle?.querySelector('[class*="_ViewToggleModelLabel_"]');
|
|
1240
|
+
const toggleValues = String(
|
|
1241
|
+
toggle?.hasAttribute("data-model-picker-view-toggle")
|
|
1242
|
+
? (toggleModelLabel?.textContent ?? toggle.innerText)
|
|
1243
|
+
: "",
|
|
1244
|
+
).split("\n").map((value) => value.trim()).filter(Boolean);
|
|
1245
|
+
if (toggleValues.length) return toggleValues[0];
|
|
1172
1246
|
const row = nativeModelPickerRow(menu);
|
|
1173
1247
|
const values = String(row?.innerText ?? "").split("\n").map((value) => value.trim()).filter(Boolean);
|
|
1174
1248
|
if (values.length > 1) return values.at(-1);
|
|
@@ -1699,9 +1773,24 @@ export function createInjectionSource(features, {
|
|
|
1699
1773
|
}
|
|
1700
1774
|
}
|
|
1701
1775
|
|
|
1776
|
+
function pruneNativeModelToggleHandlers() {
|
|
1777
|
+
for (const [toggle, handlers] of modelSelectorNativeToggleHandlers) {
|
|
1778
|
+
if (toggle.isConnected) continue;
|
|
1779
|
+
toggle.removeEventListener("click", handlers.openModels);
|
|
1780
|
+
toggle.removeEventListener("keydown", handlers.onKeyDown);
|
|
1781
|
+
modelSelectorNativeToggleHandlers.delete(toggle);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1702
1785
|
function closeControllerModelMenu() {
|
|
1703
1786
|
const record = modelSelectorControllerMenu;
|
|
1704
1787
|
if (!record) return false;
|
|
1788
|
+
const placeholder = document.querySelector(
|
|
1789
|
+
'[data-codex-intelligence-trigger] [class*="_ModelPickerTriggerPlaceholder_"]',
|
|
1790
|
+
);
|
|
1791
|
+
if (placeholder && record.placeholderText != null) {
|
|
1792
|
+
placeholder.textContent = record.placeholderText;
|
|
1793
|
+
}
|
|
1705
1794
|
record.button.setAttribute("aria-expanded", "false");
|
|
1706
1795
|
record.parentMenu.style.position = record.position;
|
|
1707
1796
|
record.parentMenu.style.overflow = record.overflow;
|
|
@@ -1783,10 +1872,17 @@ export function createInjectionSource(features, {
|
|
|
1783
1872
|
});
|
|
1784
1873
|
renderEnhancedModelMenu(menu, selector);
|
|
1785
1874
|
|
|
1875
|
+
const placeholder = document.querySelector(
|
|
1876
|
+
'[data-codex-intelligence-trigger] [class*="_ModelPickerTriggerPlaceholder_"]',
|
|
1877
|
+
);
|
|
1878
|
+
const placeholderText = placeholder?.textContent ?? null;
|
|
1879
|
+
if (placeholder) placeholder.textContent = locale === "zh-CN" ? "选择模型" : "Select model";
|
|
1880
|
+
|
|
1786
1881
|
modelSelectorControllerMenu = {
|
|
1787
1882
|
menu,
|
|
1788
1883
|
parentMenu,
|
|
1789
1884
|
button: modelButton,
|
|
1885
|
+
placeholderText,
|
|
1790
1886
|
position: parentMenu.style.position,
|
|
1791
1887
|
overflow: parentMenu.style.overflow,
|
|
1792
1888
|
};
|
|
@@ -2057,6 +2153,8 @@ export function createInjectionSource(features, {
|
|
|
2057
2153
|
"ViewToggle",
|
|
2058
2154
|
"ViewToggleContent",
|
|
2059
2155
|
"ViewToggleIcon",
|
|
2156
|
+
"ViewToggleModelLabel",
|
|
2157
|
+
"ViewToggleEffortLabel",
|
|
2060
2158
|
"ViewControls",
|
|
2061
2159
|
"FastModeToggle",
|
|
2062
2160
|
"FastModeToggleContent",
|
|
@@ -2070,6 +2168,11 @@ export function createInjectionSource(features, {
|
|
|
2070
2168
|
shell.setAttribute("data-reduced-motion", String(matchMedia("(prefers-reduced-motion: reduce)").matches));
|
|
2071
2169
|
shell.setAttribute("data-transitions-ready", "false");
|
|
2072
2170
|
const nativeRow = nativeModelPickerRow(parentMenu);
|
|
2171
|
+
const controller = nativeComposerModelController();
|
|
2172
|
+
const fastOption = controller?.serviceTierOptions?.find((option) => option?.value === "priority") ?? null;
|
|
2173
|
+
const nativeModel = nativeCatalogModelFor(identity);
|
|
2174
|
+
const supportsFast = Boolean(nativeModel?.slug.toLowerCase().startsWith("gpt-") && fastOption);
|
|
2175
|
+
shell.setAttribute("data-codex-model-slider-has-fast", String(supportsFast));
|
|
2073
2176
|
const modelButton = document.createElement("div");
|
|
2074
2177
|
modelButton.className = classes.ViewToggle;
|
|
2075
2178
|
modelButton.setAttribute("role", "button");
|
|
@@ -2081,14 +2184,31 @@ export function createInjectionSource(features, {
|
|
|
2081
2184
|
const buttonContent = document.createElement("span");
|
|
2082
2185
|
buttonContent.className = classes.ViewToggleContent;
|
|
2083
2186
|
const buttonLabel = document.createElement("span");
|
|
2187
|
+
buttonLabel.className = classes.ViewToggleModelLabel;
|
|
2188
|
+
buttonLabel.setAttribute("data-codex-model-slider-model-label", "");
|
|
2084
2189
|
buttonLabel.textContent = modelDisplayLabel(identity, selector);
|
|
2085
|
-
const
|
|
2190
|
+
const effortText = selectedEffortVisible ? document.createElement("span") : null;
|
|
2191
|
+
if (effortText) {
|
|
2192
|
+
effortText.className = classes.ViewToggleEffortLabel;
|
|
2193
|
+
effortText.textContent = effortLabel(selectedEffort);
|
|
2194
|
+
effortText.setAttribute("data-accent", "true");
|
|
2195
|
+
effortText.setAttribute("data-maximum", String(selectedEffort === "ultra"));
|
|
2196
|
+
}
|
|
2197
|
+
// 0.152.1 起原生头行 aria-label 为 "Select model",nativeModelPickerRow
|
|
2198
|
+
// 不再命中;优先从 view-toggle 行取 chevron,旧结构走原路径兜底。
|
|
2199
|
+
const nativeChevron = (
|
|
2200
|
+
parentMenu?.querySelector("[data-model-picker-view-toggle] svg")
|
|
2201
|
+
?? nativeRow?.querySelector("svg")
|
|
2202
|
+
)?.cloneNode(true);
|
|
2086
2203
|
if (nativeChevron) {
|
|
2087
2204
|
nativeChevron.className.baseVal = classes.ViewToggleIcon;
|
|
2088
2205
|
nativeChevron.setAttribute("aria-hidden", "true");
|
|
2089
|
-
buttonContent.append(buttonLabel
|
|
2206
|
+
buttonContent.append(buttonLabel);
|
|
2207
|
+
if (effortText) buttonContent.append(effortText);
|
|
2208
|
+
buttonContent.append(nativeChevron);
|
|
2090
2209
|
} else {
|
|
2091
2210
|
buttonContent.append(buttonLabel);
|
|
2211
|
+
if (effortText) buttonContent.append(effortText);
|
|
2092
2212
|
}
|
|
2093
2213
|
modelButton.append(buttonContent);
|
|
2094
2214
|
const openModels = () => openControllerModelMenu(parentMenu, modelButton, selector);
|
|
@@ -2103,10 +2223,6 @@ export function createInjectionSource(features, {
|
|
|
2103
2223
|
viewControls.className = classes.ViewControls;
|
|
2104
2224
|
viewControls.setAttribute("data-expanded", "false");
|
|
2105
2225
|
viewControls.setAttribute("data-ultra-warning-visible", "false");
|
|
2106
|
-
const controller = nativeComposerModelController();
|
|
2107
|
-
const fastOption = controller?.serviceTierOptions?.find((option) => option?.value === "priority") ?? null;
|
|
2108
|
-
const nativeModel = nativeCatalogModelFor(identity);
|
|
2109
|
-
const supportsFast = Boolean(nativeModel?.slug.toLowerCase().startsWith("gpt-") && fastOption);
|
|
2110
2226
|
const fastEnabled = Boolean(
|
|
2111
2227
|
supportsFast && (
|
|
2112
2228
|
controller.selectedServiceTier?.id === (fastOption.tier?.id ?? "priority")
|
|
@@ -2257,6 +2373,20 @@ export function createInjectionSource(features, {
|
|
|
2257
2373
|
return shell;
|
|
2258
2374
|
}
|
|
2259
2375
|
|
|
2376
|
+
function centerGenericModelPicker(parentMenu) {
|
|
2377
|
+
const trigger = document.querySelector("[data-codex-intelligence-trigger]");
|
|
2378
|
+
if (!trigger) return;
|
|
2379
|
+
const menuRect = parentMenu.getBoundingClientRect();
|
|
2380
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
2381
|
+
if (!(menuRect.width > 0 && triggerRect.width > 0)) return;
|
|
2382
|
+
const previousShift = Number.parseFloat(
|
|
2383
|
+
parentMenu.style.getPropertyValue("--codex-model-slider-menu-center-shift"),
|
|
2384
|
+
) || 0;
|
|
2385
|
+
const unshiftedCenter = menuRect.left + (menuRect.width / 2) - previousShift;
|
|
2386
|
+
const nextShift = triggerRect.left + (triggerRect.width / 2) - unshiftedCenter;
|
|
2387
|
+
parentMenu.style.setProperty("--codex-model-slider-menu-center-shift", `${nextShift}px`);
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2260
2390
|
function enhanceGenericModelPicker(parentMenu, selector) {
|
|
2261
2391
|
const identity = modelIdentity(nativeModelValue(parentMenu));
|
|
2262
2392
|
const model = modelDefinitionFor(identity, selector);
|
|
@@ -2308,7 +2438,10 @@ export function createInjectionSource(features, {
|
|
|
2308
2438
|
const canUpgradeFallback = Boolean(
|
|
2309
2439
|
existing?.querySelector("[data-codex-model-slider-fallback]") && nativeTemplateReady,
|
|
2310
2440
|
);
|
|
2311
|
-
if (existing?.getAttribute("data-codex-model-slider-generic") === key && !canUpgradeFallback)
|
|
2441
|
+
if (existing?.getAttribute("data-codex-model-slider-generic") === key && !canUpgradeFallback) {
|
|
2442
|
+
centerGenericModelPicker(parentMenu);
|
|
2443
|
+
return true;
|
|
2444
|
+
}
|
|
2312
2445
|
existing?.remove();
|
|
2313
2446
|
const nativeContainer = parentMenu.firstElementChild;
|
|
2314
2447
|
if (!nativeContainer) return false;
|
|
@@ -2321,38 +2454,76 @@ export function createInjectionSource(features, {
|
|
|
2321
2454
|
nativeContainer.style.display = "none";
|
|
2322
2455
|
shell.setAttribute("data-codex-model-slider-generic", key);
|
|
2323
2456
|
parentMenu.append(shell);
|
|
2457
|
+
centerGenericModelPicker(parentMenu);
|
|
2324
2458
|
return true;
|
|
2325
2459
|
}
|
|
2326
2460
|
|
|
2327
|
-
function
|
|
2328
|
-
if (enhanceGenericModelPicker(parentMenu, selector)) return;
|
|
2329
|
-
const toggle = parentMenu.querySelector("[data-model-picker-view-toggle]");
|
|
2330
|
-
if (!toggle) {
|
|
2331
|
-
enhanceGenericModelPicker(parentMenu, selector);
|
|
2332
|
-
return;
|
|
2333
|
-
}
|
|
2461
|
+
function restoreGenericModelPicker(parentMenu) {
|
|
2334
2462
|
parentMenu.querySelector(":scope > [data-codex-model-slider-generic]")?.remove();
|
|
2335
2463
|
parentMenu.removeAttribute("data-codex-model-slider-generic-menu");
|
|
2464
|
+
parentMenu.style.removeProperty("--codex-model-slider-menu-center-shift");
|
|
2336
2465
|
const nativeContainer = parentMenu.firstElementChild;
|
|
2337
2466
|
if (nativeContainer && modelSelectorGenericContainers.has(nativeContainer)) {
|
|
2338
2467
|
nativeContainer.style.display = modelSelectorGenericContainers.get(nativeContainer);
|
|
2339
2468
|
modelSelectorGenericContainers.delete(nativeContainer);
|
|
2340
2469
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
function enhanceNativeModelPicker(parentMenu, selector) {
|
|
2473
|
+
if (enhanceGenericModelPicker(parentMenu, selector)) return;
|
|
2474
|
+
const toggle = parentMenu.querySelector("[data-model-picker-view-toggle]");
|
|
2475
|
+
if (toggle) {
|
|
2476
|
+
// 私有 DOM 无法满足 MCX shell 契约时,保留原生菜单作为降级路径。
|
|
2477
|
+
const raw = nativeModelValue(parentMenu);
|
|
2478
|
+
const textNode = firstVisibleTextNode(toggle);
|
|
2479
|
+
if (raw && textNode) {
|
|
2480
|
+
if (!modelSelectorOriginalToggleLabels.has(textNode)) {
|
|
2481
|
+
modelSelectorOriginalToggleLabels.set(textNode, textNode.textContent);
|
|
2482
|
+
}
|
|
2483
|
+
const label = compactModelLabel(raw);
|
|
2484
|
+
if (textNode.textContent !== label) textNode.textContent = label;
|
|
2346
2485
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2486
|
+
if (!toggle.hasAttribute("data-codex-model-slider-toggle")) {
|
|
2487
|
+
const originalAriaExpanded = toggle.getAttribute("aria-expanded");
|
|
2488
|
+
toggle.setAttribute("data-codex-model-slider-toggle", "");
|
|
2489
|
+
const openModels = (event) => {
|
|
2490
|
+
event.preventDefault();
|
|
2491
|
+
event.stopPropagation();
|
|
2492
|
+
event.stopImmediatePropagation();
|
|
2493
|
+
openControllerModelMenu(parentMenu, toggle, selector);
|
|
2494
|
+
};
|
|
2495
|
+
const onKeyDown = (event) => {
|
|
2496
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2497
|
+
openModels(event);
|
|
2498
|
+
};
|
|
2499
|
+
toggle.addEventListener("click", openModels);
|
|
2500
|
+
toggle.addEventListener("keydown", onKeyDown);
|
|
2501
|
+
modelSelectorNativeToggleHandlers.set(toggle, { openModels, onKeyDown, originalAriaExpanded });
|
|
2502
|
+
}
|
|
2503
|
+
return;
|
|
2353
2504
|
}
|
|
2354
2505
|
}
|
|
2355
2506
|
|
|
2507
|
+
// 原生 ModelText 重建前的空窗期:立即插回 MCX 标签,避免关盒后芯片
|
|
2508
|
+
// 长时间失去模型名。
|
|
2509
|
+
function restoreTriggerLabelWithoutNative(trigger, selector) {
|
|
2510
|
+
if (trigger.getAttribute("data-state") !== "closed") return;
|
|
2511
|
+
if (trigger.querySelector("[data-codex-model-slider-trigger-label]")) return;
|
|
2512
|
+
const raw = trigger.getAttribute("data-codex-model-slider-trigger-raw");
|
|
2513
|
+
if (!raw) return;
|
|
2514
|
+
const anchor = trigger.querySelector('[class*="_ModelPickerTriggerLabel_"]')
|
|
2515
|
+
?? trigger.querySelector('[class*="_ModelPickerTriggerContent_"]');
|
|
2516
|
+
if (!anchor) return;
|
|
2517
|
+
const displayLabel = document.createElement("span");
|
|
2518
|
+
displayLabel.setAttribute("data-codex-model-slider-trigger-label", "");
|
|
2519
|
+
displayLabel.textContent = modelDisplayLabel(modelIdentity(raw), selector);
|
|
2520
|
+
anchor.prepend(displayLabel);
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
function isComposerModelPlaceholder(value) {
|
|
2524
|
+
return /^(select\s+(model|effort)|选择\s*(模型|思考强度))$/i.test(String(value ?? "").trim());
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2356
2527
|
function enhanceComposerModelTrigger(selector) {
|
|
2357
2528
|
const trigger = document.querySelector("[data-codex-intelligence-trigger]");
|
|
2358
2529
|
if (!trigger) return;
|
|
@@ -2365,7 +2536,15 @@ export function createInjectionSource(features, {
|
|
|
2365
2536
|
const nativeLabels = Array.from(trigger.querySelectorAll(
|
|
2366
2537
|
'[class*="_ModelPickerTriggerModelText_"]:not([data-codex-model-slider-trigger-label])',
|
|
2367
2538
|
));
|
|
2368
|
-
if (!nativeLabels.length)
|
|
2539
|
+
if (!nativeLabels.length) {
|
|
2540
|
+
trigger.setAttribute("data-codex-model-slider-trigger", "");
|
|
2541
|
+
trigger.toggleAttribute(
|
|
2542
|
+
"data-codex-model-slider-trigger-placeholder",
|
|
2543
|
+
isComposerModelPlaceholder(trigger.innerText),
|
|
2544
|
+
);
|
|
2545
|
+
restoreTriggerLabelWithoutNative(trigger, selector);
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2369
2548
|
const visibleValue = String(nativeLabels.at(-1)?.textContent ?? "").trim();
|
|
2370
2549
|
const previousRaw = trigger.getAttribute("data-codex-model-slider-trigger-raw") ?? "";
|
|
2371
2550
|
const previousLabel = previousRaw
|
|
@@ -2376,22 +2555,37 @@ export function createInjectionSource(features, {
|
|
|
2376
2555
|
const label = modelDisplayLabel(modelIdentity(raw), selector);
|
|
2377
2556
|
trigger.setAttribute("data-codex-model-slider-trigger", "");
|
|
2378
2557
|
trigger.setAttribute("data-codex-model-slider-trigger-raw", raw);
|
|
2558
|
+
// 区分占位态(Select model / Select effort)与真实模型态:占位态沿用
|
|
2559
|
+
// 原生宽度契约,真实模型态让芯片 HUG 完整名称,避免第三方长名被截断。
|
|
2560
|
+
const placeholder = isComposerModelPlaceholder(label);
|
|
2561
|
+
trigger.toggleAttribute("data-codex-model-slider-trigger-placeholder", placeholder);
|
|
2379
2562
|
for (const nativeLabel of nativeLabels) {
|
|
2380
2563
|
let displayLabel = nativeLabel.nextElementSibling;
|
|
2381
2564
|
if (!displayLabel?.hasAttribute("data-codex-model-slider-trigger-label")) {
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
displayLabel.
|
|
2565
|
+
// 空窗期回插等场景会在别处留下现成的 MCX 标签,优先移动复用,
|
|
2566
|
+
// 避免恢复后出现两个可见名称把芯片撑宽。
|
|
2567
|
+
displayLabel = trigger.querySelector("[data-codex-model-slider-trigger-label]");
|
|
2568
|
+
if (!displayLabel) {
|
|
2569
|
+
displayLabel = document.createElement("span");
|
|
2570
|
+
displayLabel.className = nativeLabel.className;
|
|
2571
|
+
displayLabel.setAttribute("data-codex-model-slider-trigger-label", "");
|
|
2572
|
+
}
|
|
2385
2573
|
nativeLabel.after(displayLabel);
|
|
2386
2574
|
}
|
|
2387
2575
|
if (displayLabel.textContent !== label) displayLabel.textContent = label;
|
|
2388
2576
|
}
|
|
2577
|
+
// 原生开合的临时 min-width 钉定与弹层水平居中都基于对 Measurement
|
|
2578
|
+
// 探针的测量;把探针文本同步为 MCX 显示标签,原生机制即可测得
|
|
2579
|
+
// 真实显示宽度(含 110px 名称上限与 160px Content 上限)。
|
|
2580
|
+
const measurement = trigger.querySelector('[class*="_ModelPickerTriggerMeasurement_"]');
|
|
2581
|
+
if (measurement && measurement.textContent !== label) measurement.textContent = label;
|
|
2389
2582
|
}
|
|
2390
2583
|
|
|
2391
2584
|
function ensureModelSelector() {
|
|
2392
2585
|
const selector = modelSelectorFeature?.modelSelector;
|
|
2393
2586
|
if (!selector) return;
|
|
2394
2587
|
pruneModelSubmenuPositionObservers();
|
|
2588
|
+
pruneNativeModelToggleHandlers();
|
|
2395
2589
|
if (!modelSelectorStyle.isConnected) document.head?.append(modelSelectorStyle);
|
|
2396
2590
|
enhanceComposerModelTrigger(selector);
|
|
2397
2591
|
const parentMenu = nativeModelPickerMenu();
|
|
@@ -2456,6 +2650,13 @@ export function createInjectionSource(features, {
|
|
|
2456
2650
|
for (const [node, value] of modelSelectorOriginalToggleLabels) {
|
|
2457
2651
|
if (node.isConnected) node.textContent = value;
|
|
2458
2652
|
}
|
|
2653
|
+
for (const [toggle, handlers] of modelSelectorNativeToggleHandlers) {
|
|
2654
|
+
toggle.removeEventListener("click", handlers.openModels);
|
|
2655
|
+
toggle.removeEventListener("keydown", handlers.onKeyDown);
|
|
2656
|
+
toggle.removeAttribute("data-codex-model-slider-toggle");
|
|
2657
|
+
if (handlers.originalAriaExpanded == null) toggle.removeAttribute("aria-expanded");
|
|
2658
|
+
else toggle.setAttribute("aria-expanded", handlers.originalAriaExpanded);
|
|
2659
|
+
}
|
|
2459
2660
|
for (const [container, display] of modelSelectorGenericContainers) {
|
|
2460
2661
|
if (container.isConnected) container.style.display = display;
|
|
2461
2662
|
}
|
|
@@ -2476,6 +2677,7 @@ export function createInjectionSource(features, {
|
|
|
2476
2677
|
modelSelectorOriginalItems.clear();
|
|
2477
2678
|
modelSelectorOriginalToggleLabels.clear();
|
|
2478
2679
|
modelSelectorGenericContainers.clear();
|
|
2680
|
+
modelSelectorNativeToggleHandlers.clear();
|
|
2479
2681
|
}
|
|
2480
2682
|
|
|
2481
2683
|
function surfaceKey(featureId, kind, detailId = "") {
|
|
@@ -2516,6 +2718,33 @@ export function createInjectionSource(features, {
|
|
|
2516
2718
|
}, record.origin);
|
|
2517
2719
|
}
|
|
2518
2720
|
|
|
2721
|
+
function nativeSidebarTrigger() {
|
|
2722
|
+
const triggers = Array.from(document.querySelectorAll(
|
|
2723
|
+
'button[data-app-shell-sidebar-trigger="true"]',
|
|
2724
|
+
));
|
|
2725
|
+
return triggers.find((button) => isVisibleToolbarControl(button)) ?? triggers[0] ?? null;
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
function sidebarState() {
|
|
2729
|
+
const trigger = nativeSidebarTrigger();
|
|
2730
|
+
const expanded = trigger?.getAttribute("aria-expanded");
|
|
2731
|
+
const triggerRect = trigger?.getBoundingClientRect();
|
|
2732
|
+
return {
|
|
2733
|
+
available: Boolean(trigger),
|
|
2734
|
+
open: expanded === null ? sidebarRight() > 0 : expanded === "true",
|
|
2735
|
+
label: trigger?.getAttribute("aria-label") ?? "Show sidebar",
|
|
2736
|
+
leading: triggerRect?.left ?? 16,
|
|
2737
|
+
};
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2740
|
+
function postSidebarState(record, state = sidebarState()) {
|
|
2741
|
+
if (!record || record.kind !== "page") return;
|
|
2742
|
+
record.frame.contentWindow?.postMessage({
|
|
2743
|
+
type: "codex-personal:sidebar-state",
|
|
2744
|
+
...state,
|
|
2745
|
+
}, record.origin);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2519
2748
|
function registerSurface(key, feature, kind, surfaceUrl, element, frame, detailId = null) {
|
|
2520
2749
|
const record = {
|
|
2521
2750
|
key,
|
|
@@ -2535,6 +2764,7 @@ export function createInjectionSource(features, {
|
|
|
2535
2764
|
frame.addEventListener("load", () => {
|
|
2536
2765
|
queueTheme();
|
|
2537
2766
|
postSurfaceActive(record, activePageFeatureId === record.featureId && !record.element.hidden);
|
|
2767
|
+
postSidebarState(record);
|
|
2538
2768
|
});
|
|
2539
2769
|
requestSurfaceLoad(record);
|
|
2540
2770
|
return record;
|
|
@@ -2643,8 +2873,16 @@ export function createInjectionSource(features, {
|
|
|
2643
2873
|
}
|
|
2644
2874
|
|
|
2645
2875
|
function updatePageSurfacePositions() {
|
|
2646
|
-
const
|
|
2647
|
-
|
|
2876
|
+
const state = sidebarState();
|
|
2877
|
+
const left = `${state.open ? Math.max(0, sidebarRight()) : 0}px`;
|
|
2878
|
+
for (const [featureId, surface] of pageSurfaces) {
|
|
2879
|
+
surface.style.left = left;
|
|
2880
|
+
postSidebarState(surfaceRecords.get(surfaceKey(featureId, "page")), state);
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
function syncAfterNativeSidebarToggle() {
|
|
2885
|
+
queueMicrotask(updatePageSurfacePositions);
|
|
2648
2886
|
}
|
|
2649
2887
|
|
|
2650
2888
|
function threadIdentity() {
|
|
@@ -3958,6 +4196,15 @@ export function createInjectionSource(features, {
|
|
|
3958
4196
|
});
|
|
3959
4197
|
return;
|
|
3960
4198
|
}
|
|
4199
|
+
if (action === "open-sidebar") {
|
|
4200
|
+
const trigger = nativeSidebarTrigger();
|
|
4201
|
+
if (!trigger) throw new Error("The native sidebar control was not found");
|
|
4202
|
+
const state = sidebarState();
|
|
4203
|
+
if (!state.open) trigger.click();
|
|
4204
|
+
queueMicrotask(() => postSidebarState(record, { ...state, open: true }));
|
|
4205
|
+
respondToSurface(record, requestId, { ok: true, result: { opened: true } });
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
3961
4208
|
if (action === "resolve-file-paths") {
|
|
3962
4209
|
const getPathForFile = window.electronBridge?.getPathForFile;
|
|
3963
4210
|
if (typeof getPathForFile !== "function") {
|
|
@@ -4016,6 +4263,9 @@ export function createInjectionSource(features, {
|
|
|
4016
4263
|
document.addEventListener(
|
|
4017
4264
|
"click",
|
|
4018
4265
|
(event) => {
|
|
4266
|
+
if (event.target.closest?.('[data-app-shell-sidebar-trigger="true"]')) {
|
|
4267
|
+
syncAfterNativeSidebarToggle();
|
|
4268
|
+
}
|
|
4019
4269
|
if (
|
|
4020
4270
|
modelSelectorControllerMenu
|
|
4021
4271
|
&& !modelSelectorControllerMenu.menu.contains(event.target)
|
|
@@ -4081,6 +4331,7 @@ export function createInjectionSource(features, {
|
|
|
4081
4331
|
if (event.data.type === "codex-personal:ready") {
|
|
4082
4332
|
record.ready = true;
|
|
4083
4333
|
queueTheme();
|
|
4334
|
+
postSidebarState(record);
|
|
4084
4335
|
if (record.kind === "modal") {
|
|
4085
4336
|
record.frame.focus();
|
|
4086
4337
|
record.frame.contentWindow?.postMessage({
|
|
@@ -4118,7 +4369,24 @@ export function createInjectionSource(features, {
|
|
|
4118
4369
|
updatePageSurfacePositions();
|
|
4119
4370
|
updateResponsiveSummaryPresentation();
|
|
4120
4371
|
}, { signal: lifetime.signal });
|
|
4121
|
-
const ensureObserver = new MutationObserver(
|
|
4372
|
+
const ensureObserver = new MutationObserver((mutations) => {
|
|
4373
|
+
queueEnsure();
|
|
4374
|
+
const sidebarTriggerChanged = mutations.some((mutation) => {
|
|
4375
|
+
if (
|
|
4376
|
+
mutation.type === "attributes"
|
|
4377
|
+
&& mutation.target.matches?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4378
|
+
) return true;
|
|
4379
|
+
return mutation.type === "childList"
|
|
4380
|
+
&& [...mutation.addedNodes, ...mutation.removedNodes].some((node) => (
|
|
4381
|
+
node instanceof Element
|
|
4382
|
+
&& (
|
|
4383
|
+
node.matches?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4384
|
+
|| node.querySelector?.('[data-app-shell-sidebar-trigger="true"]')
|
|
4385
|
+
)
|
|
4386
|
+
));
|
|
4387
|
+
});
|
|
4388
|
+
if (sidebarTriggerChanged) updatePageSurfacePositions();
|
|
4389
|
+
});
|
|
4122
4390
|
ensureObserver.observe(document.documentElement, {
|
|
4123
4391
|
childList: true,
|
|
4124
4392
|
subtree: true,
|