dsh-auto-open-web 0.1.9 → 0.1.13
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/README.en.md +221 -211
- package/README.md +207 -191
- package/cordis.patch.yml +22 -17
- package/host-publish/DshAppWindow.dll +0 -0
- package/host-publish/DshAppWindow.exe +0 -0
- package/host-publish/DshAppWindow.pdb +0 -0
- package/lib/client.js +235 -174
- package/lib/index.js +664 -619
- package/lib/platform.js +29 -29
- package/lib/posix.js +65 -65
- package/package.json +61 -61
package/lib/client.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
// dsh-auto-open-web — Client bundle(
|
|
1
|
+
// dsh-auto-open-web — Client bundle(设置卡片;UI 完全自绘,不依赖官方组件/CSS 模板)
|
|
2
2
|
// 格式:window.__ModuleLoader__.load({ id, factory });factory(require) 的
|
|
3
|
-
// require
|
|
4
|
-
// @deepseek-ai/dsh-client-
|
|
3
|
+
// require 解析浏览器端模块表(react 为壳层静态模块,@deepseek-ai/dsh-client-runtime
|
|
4
|
+
// 为动态包)。**不** require @deepseek-ai/dsh-client-ui-primitives 等官方 UI 包。
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
// -
|
|
8
|
-
//
|
|
9
|
-
// -
|
|
10
|
-
//
|
|
11
|
-
// -
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// -
|
|
15
|
-
// -
|
|
16
|
-
//
|
|
6
|
+
// 依赖边界(与官方数据的对接面,均为公开接口;本插件声明 dsh ≥0.1.0-rc.8):
|
|
7
|
+
// - settingsScope:官方 settings 域(命名空间 `auto-open-web`;第三方命名空间
|
|
8
|
+
// 白名单自 rc.7 起已取消,rc.8 下无限制)
|
|
9
|
+
// - slots:settings.plugin.item 插槽(keyed 注册,rc.7 起要求 options.key)
|
|
10
|
+
// - locale:文案注册(zh/en/ja/ko/fr/de/ru,跟随界面语言)
|
|
11
|
+
// - dsh-client-runtime:createSnapshotStore 快照 store(缺失时内置兜底实现)
|
|
12
|
+
//
|
|
13
|
+
// 视觉(全部自产):
|
|
14
|
+
// - 卡片外壳、字段、按钮、输入框、复选/单选、徽章、图标均为手写实现;
|
|
15
|
+
// - 观感通过官方设计令牌变量(--dsw-alias-* / --dsw-static-*)对齐,浅/深色
|
|
16
|
+
// 自动跟随主题,不复刻官方任何样式表或组件代码;
|
|
17
|
+
// - CSS 经标准注入约定(<style data-plugin / data-plugin-css> 去重)挂载。
|
|
17
18
|
//
|
|
18
19
|
// 宿主保留的辅助路由(官方通道无法覆盖):
|
|
19
20
|
// POST /auto-open-web/pick-browser → 原生"浏览"对话框
|
|
@@ -26,22 +27,59 @@ window.__ModuleLoader__.load({
|
|
|
26
27
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
|
|
27
28
|
let React = require('react')
|
|
28
29
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
// ── 自绘样式(观感对齐官方设计令牌;类名全部自有 aow-*) ────────────────
|
|
31
|
+
// 卡片外壳:圆角 12、l2 边框、layer-3 底;悬停/展开态换层,折叠箭头旋转。
|
|
32
|
+
var CARD_CSS =
|
|
33
|
+
'.aow-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}' +
|
|
34
|
+
'.aow-card:hover{border-color:var(--dsw-alias-label-dimmed,var(--dsw-alias-border-l2))}' +
|
|
35
|
+
'.aow-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed,var(--dsw-alias-border-l2))}' +
|
|
36
|
+
'.aow-cardHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}' +
|
|
37
|
+
'.aow-cardHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}' +
|
|
38
|
+
'.aow-cardHeadText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}' +
|
|
39
|
+
'.aow-cardName{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}' +
|
|
40
|
+
'.aow-cardDescription{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));font-size:13px;line-height:1.5}' +
|
|
41
|
+
'.aow-cardChevron{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));flex:none;transition:transform .16s;display:inline-flex}' +
|
|
42
|
+
'.aow-cardChevronOpen{transform:rotate(180deg)}' +
|
|
43
|
+
'.aow-cardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}' +
|
|
44
|
+
'.aow-cardReadOnly{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));margin:12px 0 0;font-size:12px;line-height:1.5}' +
|
|
45
|
+
'.aow-pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}' +
|
|
46
|
+
'.aow-cardFooter{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}' +
|
|
47
|
+
'.aow-cardFailed{min-width:0;color:var(--dsw-alias-label-error,var(--dsw-alias-state-error-primary));flex:1;margin:0;font-size:12px;line-height:1.5}' +
|
|
48
|
+
// 按钮:描边(outline)与主色(save)两种,禁用半透明。
|
|
49
|
+
'.aow-btn{appearance:none;font:inherit;cursor:pointer;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5;border:1px solid transparent}' +
|
|
50
|
+
'.aow-btn:disabled{opacity:.55;cursor:default}' +
|
|
51
|
+
'.aow-btnOutline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}' +
|
|
52
|
+
'.aow-btnOutline:hover:not(:disabled){color:var(--dsw-alias-label-primary)}' +
|
|
53
|
+
'.aow-btnPrimary{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-inverse,#fff);border-color:var(--dsw-alias-brand-primary);font-weight:600}' +
|
|
54
|
+
'.aow-btnPrimary:hover:not(:disabled){filter:brightness(.95)}'
|
|
55
|
+
// 字段区:label 行 + 控件 + hint;相邻字段以 l2 分隔;徽章/恢复默认同观感。
|
|
56
|
+
var FIELDS_CSS =
|
|
57
|
+
'.aow-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}' +
|
|
58
|
+
'.aow-field+.aow-field{border-top:1px solid var(--dsw-alias-border-l2)}' +
|
|
59
|
+
'.aow-fieldHead{align-items:center;gap:8px;display:flex}' +
|
|
60
|
+
'.aow-fieldLabel{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}' +
|
|
61
|
+
'.aow-badges{align-items:center;gap:8px;display:inline-flex}' +
|
|
62
|
+
'.aow-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}' +
|
|
63
|
+
'.aow-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}' +
|
|
64
|
+
'.aow-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}' +
|
|
65
|
+
'.aow-reset:disabled{cursor:default}' +
|
|
66
|
+
'.aow-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}' +
|
|
67
|
+
'.aow-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}' +
|
|
68
|
+
'.aow-input:disabled{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));cursor:default}' +
|
|
69
|
+
'.aow-inputInvalid{border-color:var(--dsw-alias-label-error,var(--dsw-alias-state-error-primary))}' +
|
|
70
|
+
'.aow-invalid{color:var(--dsw-alias-label-error,var(--dsw-alias-state-error-primary));margin:0;font-size:12px;line-height:1.5}' +
|
|
71
|
+
'.aow-hint{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;line-height:1.5}'
|
|
72
|
+
// 布局与杂项:行排列、复选/单选、测试结果状态。
|
|
73
|
+
var CONTROLS_CSS =
|
|
37
74
|
'.aow-row{display:flex;gap:8px;align-items:center}' +
|
|
38
|
-
'.aow-grow{flex:1;min-width:0}' +
|
|
39
75
|
'.aow-check{display:flex;align-items:center;gap:8px;cursor:pointer}' +
|
|
40
76
|
'.aow-check input{accent-color:var(--dsw-alias-brand-primary);width:15px;height:15px;margin:0;flex:none}' +
|
|
41
77
|
'.aow-check input:disabled{cursor:default}' +
|
|
42
78
|
'.aow-test-ok{color:var(--dsw-alias-state-success-primary);margin:4px 0 0;font-size:12px;line-height:1.5}' +
|
|
43
79
|
'.aow-test-fail{color:var(--dsw-alias-label-error,var(--dsw-alias-state-error-primary));margin:4px 0 0;font-size:12px;line-height:1.5}'
|
|
44
|
-
var
|
|
80
|
+
var CARD_TAG = 'dsh-auto-open-web/Card.module.css'
|
|
81
|
+
var FIELDS_TAG = 'dsh-auto-open-web/Fields.module.css'
|
|
82
|
+
var CONTROLS_TAG = 'dsh-auto-open-web/Controls.module.css'
|
|
45
83
|
function injectCss(tagId, css) {
|
|
46
84
|
if (typeof document === 'undefined') return
|
|
47
85
|
if (document.querySelector('style[data-plugin-css=' + JSON.stringify(tagId) + ']') !== null) return
|
|
@@ -53,29 +91,17 @@ window.__ModuleLoader__.load({
|
|
|
53
91
|
}
|
|
54
92
|
injectCss(CARD_TAG, CARD_CSS)
|
|
55
93
|
injectCss(FIELDS_TAG, FIELDS_CSS)
|
|
56
|
-
injectCss(
|
|
94
|
+
injectCss(CONTROLS_TAG, CONTROLS_CSS)
|
|
57
95
|
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// 各 require 独立容错:任一可选模块缺失不得拖垮其余模块(尤其 runtime)。
|
|
62
|
-
var prim = null
|
|
96
|
+
// ── 共享模块 ─────────────────────────────────────────────────────────
|
|
97
|
+
// 仅 react(壳层静态模块)+ dsh-client-runtime(动态包,快照 store)。
|
|
98
|
+
// runtime 缺失或版本不含 createSnapshotStore 时退化为内置最小实现。
|
|
63
99
|
var runtime = null
|
|
64
|
-
try {
|
|
65
|
-
prim = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
66
|
-
} catch (e) {
|
|
67
|
-
console.error('[auto-open-web] primitives require failed:', e !== null && e !== undefined && e.message !== undefined ? e.message : String(e))
|
|
68
|
-
}
|
|
69
100
|
try {
|
|
70
101
|
runtime = require('@deepseek-ai/dsh-client-runtime')
|
|
71
102
|
} catch (e) {
|
|
72
103
|
console.error('[auto-open-web] runtime require failed:', e !== null && e !== undefined && e.message !== undefined ? e.message : String(e))
|
|
73
104
|
}
|
|
74
|
-
var Button = prim !== null && prim.Button !== undefined ? prim.Button : null
|
|
75
|
-
var Input = prim !== null && prim.Input !== undefined ? prim.Input : null
|
|
76
|
-
var ChevronIcon = prim !== null && prim.IconChevronDownOutline14 !== undefined ? prim.IconChevronDownOutline14 : null
|
|
77
|
-
// 快照 store 契约与官方一致:{ getSnapshot, subscribe, set }。runtime 缺失
|
|
78
|
-
// 或版本不含 createSnapshotStore 时退化为内置最小实现(卡片仍可用)。
|
|
79
105
|
var createSnapshotStore = runtime !== null && runtime.createSnapshotStore !== undefined ? runtime.createSnapshotStore : fallbackSnapshotStore
|
|
80
106
|
function fallbackSnapshotStore(init) {
|
|
81
107
|
let value = init
|
|
@@ -95,18 +121,49 @@ window.__ModuleLoader__.load({
|
|
|
95
121
|
}
|
|
96
122
|
}
|
|
97
123
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
// ── 自绘基础控件 ─────────────────────────────────────────────────────
|
|
125
|
+
/** 14px 折叠箭头(手绘 SVG,currentColor 跟随令牌)。 */
|
|
126
|
+
function IconChevronDown(props) {
|
|
127
|
+
return React.createElement('svg', {
|
|
128
|
+
width: 14,
|
|
129
|
+
height: 14,
|
|
130
|
+
viewBox: '0 0 14 14',
|
|
131
|
+
fill: 'none',
|
|
132
|
+
'aria-hidden': true,
|
|
133
|
+
className: props.className
|
|
134
|
+
},
|
|
135
|
+
React.createElement('path', {
|
|
136
|
+
d: 'M3.5 5.25L7 8.75L10.5 5.25',
|
|
137
|
+
stroke: 'currentColor',
|
|
138
|
+
strokeWidth: 1.5,
|
|
139
|
+
strokeLinecap: 'round',
|
|
140
|
+
strokeLinejoin: 'round'
|
|
141
|
+
})
|
|
142
|
+
)
|
|
109
143
|
}
|
|
144
|
+
/** 按钮:variant = outline | primary。 */
|
|
145
|
+
function Btn(props) {
|
|
146
|
+
const cls = 'aow-btn ' + (props.variant === 'primary' ? 'aow-btnPrimary' : 'aow-btnOutline')
|
|
147
|
+
return React.createElement('button', {
|
|
148
|
+
type: 'button',
|
|
149
|
+
className: cls,
|
|
150
|
+
disabled: props.disabled === true,
|
|
151
|
+
onClick: props.onClick
|
|
152
|
+
}, props.children)
|
|
153
|
+
}
|
|
154
|
+
/** 文本输入框。 */
|
|
155
|
+
function TextInput(props) {
|
|
156
|
+
return React.createElement('input', {
|
|
157
|
+
id: props.id,
|
|
158
|
+
className: 'aow-input' + (props.invalid === true ? ' aow-inputInvalid' : ''),
|
|
159
|
+
type: 'text',
|
|
160
|
+
value: props.value,
|
|
161
|
+
placeholder: props.placeholder !== undefined ? props.placeholder : '',
|
|
162
|
+
disabled: props.disabled === true,
|
|
163
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
/** 复选行(label + 说明文字)。 */
|
|
110
167
|
function Checkbox(props) {
|
|
111
168
|
return React.createElement('label', { className: 'aow-check' },
|
|
112
169
|
React.createElement('input', {
|
|
@@ -115,9 +172,10 @@ window.__ModuleLoader__.load({
|
|
|
115
172
|
disabled: props.disabled === true,
|
|
116
173
|
onChange: (event) => props.onChange(event.target.checked)
|
|
117
174
|
}),
|
|
118
|
-
React.createElement('span', { className: '
|
|
175
|
+
React.createElement('span', { className: 'aow-hint' }, props.children)
|
|
119
176
|
)
|
|
120
177
|
}
|
|
178
|
+
/** 单选行。 */
|
|
121
179
|
function Radio(props) {
|
|
122
180
|
return React.createElement('label', { className: 'aow-check' },
|
|
123
181
|
React.createElement('input', {
|
|
@@ -127,86 +185,81 @@ window.__ModuleLoader__.load({
|
|
|
127
185
|
disabled: props.disabled === true,
|
|
128
186
|
onChange: () => props.onChange(props.value)
|
|
129
187
|
}),
|
|
130
|
-
React.createElement('span', { className: '
|
|
188
|
+
React.createElement('span', { className: 'aow-hint' }, props.children)
|
|
131
189
|
)
|
|
132
190
|
}
|
|
133
|
-
/**
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
React.createElement('span', { className: '
|
|
138
|
-
|
|
139
|
-
)
|
|
191
|
+
/** 字段头部徽章组:"已覆盖" + "恢复默认"(或仅静态徽章)。 */
|
|
192
|
+
function FieldBadges(props) {
|
|
193
|
+
const children = []
|
|
194
|
+
if (props.static !== undefined && props.static !== null) {
|
|
195
|
+
children.push(React.createElement('span', { className: 'aow-badge' }, props.static))
|
|
196
|
+
}
|
|
197
|
+
if (props.overridden === true) {
|
|
198
|
+
children.push(
|
|
199
|
+
React.createElement('span', { className: 'aow-badge' }, props.overriddenLabel),
|
|
200
|
+
React.createElement('button', { type: 'button', className: 'aow-reset', disabled: props.disabled === true, onClick: props.onReset }, props.resetLabel)
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
if (children.length === 0) return null
|
|
204
|
+
return React.createElement('span', { className: 'aow-badges' }, ...children)
|
|
140
205
|
}
|
|
141
206
|
|
|
142
|
-
//
|
|
143
|
-
|
|
207
|
+
// ── 自绘卡片外壳(观感对齐官方设置卡片) ─────────────────────────────
|
|
208
|
+
// 折叠为卡片本地状态;展开时显示只读提示、控件、页脚(放弃/保存)。
|
|
209
|
+
// 命名空间不可用时整卡不渲染(部署未组合本插件时不留痕迹)。
|
|
210
|
+
function Card(props) {
|
|
144
211
|
const [open, setOpen] = React.useState(false)
|
|
145
212
|
const { state } = props
|
|
146
213
|
if (!state.available) return null
|
|
147
214
|
const title = props.t(props.titleKey)
|
|
148
215
|
const blocked = !state.dirty || state.invalid || state.saving
|
|
149
|
-
return React.createElement('li', { className: '
|
|
216
|
+
return React.createElement('li', { className: 'aow-card' + (open ? ' aow-cardOpen' : '') },
|
|
150
217
|
React.createElement('button', {
|
|
151
218
|
type: 'button',
|
|
152
|
-
className: '
|
|
219
|
+
className: 'aow-cardHeader',
|
|
153
220
|
'aria-expanded': open,
|
|
154
221
|
'aria-label': (open ? props.t('collapse') : props.t('expand')) + ': ' + title,
|
|
155
222
|
onClick: () => setOpen(!open)
|
|
156
223
|
},
|
|
157
|
-
React.createElement('span', { className: '
|
|
158
|
-
React.createElement('span', { className: '
|
|
159
|
-
React.createElement('span', { className: '
|
|
224
|
+
React.createElement('span', { className: 'aow-cardHeadText' },
|
|
225
|
+
React.createElement('span', { className: 'aow-cardName' }, title),
|
|
226
|
+
React.createElement('span', { className: 'aow-cardDescription' }, props.t(props.descriptionKey))
|
|
160
227
|
),
|
|
161
|
-
state.dirty ? React.createElement('span', { className: '
|
|
162
|
-
|
|
163
|
-
? React.createElement(ChevronIcon, { className: 'YyYd_a_chevron' + (open ? ' YyYd_a_chevronOpen' : '') })
|
|
164
|
-
: React.createElement('span', { className: 'YyYd_a_chevron' + (open ? ' YyYd_a_chevronOpen' : '') }, '▾')
|
|
228
|
+
state.dirty ? React.createElement('span', { className: 'aow-pending' }, props.t('unsaved')) : null,
|
|
229
|
+
React.createElement(IconChevronDown, { className: 'aow-cardChevron' + (open ? ' aow-cardChevronOpen' : '') })
|
|
165
230
|
),
|
|
166
|
-
open ? React.createElement('div', { className: '
|
|
167
|
-
!state.writable ? React.createElement('p', { className: '
|
|
231
|
+
open ? React.createElement('div', { className: 'aow-cardBody' },
|
|
232
|
+
!state.writable ? React.createElement('p', { className: 'aow-cardReadOnly', role: 'status' }, props.t('readOnly')) : null,
|
|
168
233
|
props.children,
|
|
169
|
-
React.createElement('div', { className: '
|
|
170
|
-
state.failed ? React.createElement('p', { className: '
|
|
171
|
-
React.createElement(
|
|
172
|
-
React.createElement(
|
|
234
|
+
React.createElement('div', { className: 'aow-cardFooter' },
|
|
235
|
+
state.failed ? React.createElement('p', { className: 'aow-cardFailed', role: 'status' }, props.t('saveFailed')) : null,
|
|
236
|
+
React.createElement(Btn, { disabled: !state.dirty || state.saving, onClick: props.onDiscard }, props.t('discard')),
|
|
237
|
+
React.createElement(Btn, { variant: 'primary', disabled: blocked, onClick: props.onSave }, state.saving ? props.t('saving') : props.t('save'))
|
|
173
238
|
)
|
|
174
239
|
) : null
|
|
175
240
|
)
|
|
176
241
|
}
|
|
177
242
|
|
|
178
|
-
//
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
props.
|
|
184
|
-
|
|
185
|
-
React.createElement('span', { className: 'At1oFq_badge' }, props.overriddenLabel),
|
|
186
|
-
React.createElement('button', { type: 'button', className: 'At1oFq_reset', disabled: props.disabled, onClick: props.onReset }, props.resetLabel)
|
|
187
|
-
)
|
|
188
|
-
: null
|
|
243
|
+
// ── 自绘字段布局(label 行 + 控件 + hint + 可选页脚) ──────────────────
|
|
244
|
+
function Field(props) {
|
|
245
|
+
const hintText = props.invalid === true ? props.invalidLabel : props.hint
|
|
246
|
+
return React.createElement('div', { className: 'aow-field' },
|
|
247
|
+
React.createElement('div', { className: 'aow-fieldHead' },
|
|
248
|
+
React.createElement('span', { className: 'aow-fieldLabel' }, props.label),
|
|
249
|
+
props.badges !== undefined && props.badges !== null ? props.badges : null
|
|
189
250
|
),
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
placeholder: props.placeholder !== undefined ? props.placeholder : '',
|
|
197
|
-
disabled: props.disabled,
|
|
198
|
-
onChange: (event) => props.onEdit(event.target.value)
|
|
199
|
-
}),
|
|
200
|
-
props.extra !== undefined ? props.extra : null
|
|
201
|
-
),
|
|
202
|
-
React.createElement('p', { className: props.invalid ? 'At1oFq_invalid' : 'At1oFq_hint' },
|
|
203
|
-
props.invalid ? props.invalidLabel : props.hint
|
|
204
|
-
),
|
|
205
|
-
props.footer !== undefined ? props.footer : null
|
|
251
|
+
props.control,
|
|
252
|
+
// hint 为空时不渲染段落(提示文字已内联在控件里,如复选框行)
|
|
253
|
+
hintText !== undefined && hintText !== null && hintText !== ''
|
|
254
|
+
? React.createElement('p', { className: props.invalid === true ? 'aow-invalid' : 'aow-hint' }, hintText)
|
|
255
|
+
: null,
|
|
256
|
+
props.footer !== undefined && props.footer !== null ? props.footer : null
|
|
206
257
|
)
|
|
207
258
|
}
|
|
208
259
|
|
|
209
|
-
//
|
|
260
|
+
// ── 表单模型(字段规格 + staged 草稿 + 保存计划 + 落地校验) ───────────
|
|
261
|
+
// 与官方数据契约一致:scope 提供 { getSnapshot() → { status, writable,
|
|
262
|
+
// value, base, user }, set/unset };写后以 user 层落地为准。
|
|
210
263
|
/** 自由文本字段:空草稿 = 清除(恢复默认)。 */
|
|
211
264
|
function textField(field) {
|
|
212
265
|
return {
|
|
@@ -235,7 +288,7 @@ window.__ModuleLoader__.load({
|
|
|
235
288
|
}
|
|
236
289
|
}
|
|
237
290
|
/** 表单:staged 草稿 → 保存计划;写后以 user 层落地为准。 */
|
|
238
|
-
function
|
|
291
|
+
function FormModel(scope, specs) {
|
|
239
292
|
this.scope = scope
|
|
240
293
|
this.specs = new Map(specs.map((spec) => [spec.field, spec]))
|
|
241
294
|
this.staged = new Map()
|
|
@@ -246,14 +299,14 @@ window.__ModuleLoader__.load({
|
|
|
246
299
|
this.publish()
|
|
247
300
|
})
|
|
248
301
|
}
|
|
249
|
-
|
|
302
|
+
FormModel.prototype.bind = function (project) {
|
|
250
303
|
const store = createSnapshotStore(project())
|
|
251
304
|
this.listeners.add(() => {
|
|
252
305
|
store.set(project())
|
|
253
306
|
})
|
|
254
307
|
return store
|
|
255
308
|
}
|
|
256
|
-
|
|
309
|
+
FormModel.prototype.shell = function () {
|
|
257
310
|
const snapshot = this.scope.getSnapshot()
|
|
258
311
|
const plan = this.plan()
|
|
259
312
|
return {
|
|
@@ -265,7 +318,7 @@ window.__ModuleLoader__.load({
|
|
|
265
318
|
failed: this.failed
|
|
266
319
|
}
|
|
267
320
|
}
|
|
268
|
-
|
|
321
|
+
FormModel.prototype.field = function (field) {
|
|
269
322
|
const staged = this.staged.get(field)
|
|
270
323
|
const spec = this.specs.get(field)
|
|
271
324
|
if (spec === undefined) throw new Error('plugin card has no field ' + field)
|
|
@@ -281,7 +334,7 @@ window.__ModuleLoader__.load({
|
|
|
281
334
|
invalid: write === undefined
|
|
282
335
|
}
|
|
283
336
|
}
|
|
284
|
-
|
|
337
|
+
FormModel.prototype.actions = function () {
|
|
285
338
|
return {
|
|
286
339
|
edit: (field, text) => {
|
|
287
340
|
this.stage(field, { text, clear: false })
|
|
@@ -300,7 +353,7 @@ window.__ModuleLoader__.load({
|
|
|
300
353
|
}
|
|
301
354
|
}
|
|
302
355
|
}
|
|
303
|
-
|
|
356
|
+
FormModel.prototype.save = function () {
|
|
304
357
|
const plan = this.plan()
|
|
305
358
|
const writes = plan.flatMap((item) => item.run === undefined ? [] : [item.run])
|
|
306
359
|
if (plan.length === 0 || this.saving || writes.length !== plan.length) return
|
|
@@ -321,7 +374,7 @@ window.__ModuleLoader__.load({
|
|
|
321
374
|
this.publish()
|
|
322
375
|
})
|
|
323
376
|
}
|
|
324
|
-
|
|
377
|
+
FormModel.prototype.plan = function () {
|
|
325
378
|
const plan = []
|
|
326
379
|
for (const [field, staged] of this.staged) {
|
|
327
380
|
const spec = this.specs.get(field)
|
|
@@ -337,45 +390,45 @@ window.__ModuleLoader__.load({
|
|
|
337
390
|
}
|
|
338
391
|
return plan
|
|
339
392
|
}
|
|
340
|
-
|
|
393
|
+
FormModel.prototype.stage = function (field, edit) {
|
|
341
394
|
this.staged.set(field, edit)
|
|
342
395
|
this.failed = false
|
|
343
396
|
this.publish()
|
|
344
397
|
}
|
|
345
|
-
|
|
398
|
+
FormModel.prototype.clear = async function (field) {
|
|
346
399
|
await this.scope.unset(field)
|
|
347
400
|
return !this.stored(field)
|
|
348
401
|
}
|
|
349
|
-
|
|
402
|
+
FormModel.prototype.store = async function (field, value) {
|
|
350
403
|
await this.scope.set(field, value)
|
|
351
404
|
const user = this.userLayer()
|
|
352
405
|
return user !== undefined && user !== null && user[field] === value
|
|
353
406
|
}
|
|
354
|
-
|
|
407
|
+
FormModel.prototype.snapshotOf = function () {
|
|
355
408
|
return this.scope.getSnapshot()
|
|
356
409
|
}
|
|
357
|
-
|
|
410
|
+
FormModel.prototype.sectionValue = function (field) {
|
|
358
411
|
const snapshot = this.snapshotOf()
|
|
359
412
|
return snapshot.value !== undefined && snapshot.value !== null ? snapshot.value[field] : undefined
|
|
360
413
|
}
|
|
361
|
-
|
|
414
|
+
FormModel.prototype.baseValue = function (field) {
|
|
362
415
|
const snapshot = this.snapshotOf()
|
|
363
416
|
return snapshot.base !== undefined && snapshot.base !== null ? snapshot.base[field] : undefined
|
|
364
417
|
}
|
|
365
|
-
|
|
418
|
+
FormModel.prototype.userLayer = function () {
|
|
366
419
|
return this.snapshotOf().user
|
|
367
420
|
}
|
|
368
|
-
|
|
421
|
+
FormModel.prototype.stored = function (field) {
|
|
369
422
|
const user = this.userLayer()
|
|
370
423
|
return user !== undefined && user !== null && Object.prototype.hasOwnProperty.call(user, field)
|
|
371
424
|
}
|
|
372
|
-
|
|
425
|
+
FormModel.prototype.publish = function () {
|
|
373
426
|
for (const listener of this.listeners) listener()
|
|
374
427
|
}
|
|
375
428
|
|
|
376
|
-
//
|
|
429
|
+
// ── 卡片控制器:scope → FormModel → 投影 store + 动作面 ───────────────
|
|
377
430
|
function AutoOpenCardController(scope) {
|
|
378
|
-
this.form = new
|
|
431
|
+
this.form = new FormModel(scope, [boolField('appWindow'), windowKindField('windowKind'), textField('browserPath'), boolField('exitOnWindowClose')])
|
|
379
432
|
this.store = this.form.bind(() => this.projection())
|
|
380
433
|
}
|
|
381
434
|
AutoOpenCardController.prototype.projection = function () {
|
|
@@ -394,7 +447,7 @@ window.__ModuleLoader__.load({
|
|
|
394
447
|
}
|
|
395
448
|
}
|
|
396
449
|
|
|
397
|
-
//
|
|
450
|
+
// ── 设置卡片页面(自绘组件拼装) ─────────────────────────────────────
|
|
398
451
|
function AutoOpenSettingsPage(props) {
|
|
399
452
|
const { t } = props
|
|
400
453
|
const state = props.useAutoOpenCard((snapshot) => snapshot)
|
|
@@ -439,7 +492,15 @@ window.__ModuleLoader__.load({
|
|
|
439
492
|
|
|
440
493
|
const browserDisabled = !state.writable || state.windowKind.text !== 'browser'
|
|
441
494
|
|
|
442
|
-
|
|
495
|
+
const badgesFor = (field) => React.createElement(FieldBadges, {
|
|
496
|
+
overridden: state[field].overridden,
|
|
497
|
+
disabled: !state.writable,
|
|
498
|
+
overriddenLabel: t('overridden'),
|
|
499
|
+
resetLabel: t('reset'),
|
|
500
|
+
onReset: () => props.resetField(field)
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
return React.createElement(Card, {
|
|
443
504
|
t,
|
|
444
505
|
titleKey: 'title',
|
|
445
506
|
descriptionKey: 'description',
|
|
@@ -448,40 +509,38 @@ window.__ModuleLoader__.load({
|
|
|
448
509
|
onDiscard: props.discard
|
|
449
510
|
},
|
|
450
511
|
// ---- 独立应用窗口 ----
|
|
451
|
-
React.createElement(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
React.createElement(Checkbox, { checked: state.appWindow.text === true, disabled: !state.writable, onChange: (v) => props.edit('appWindow', v) }, t('appWindowHint'))
|
|
457
|
-
),
|
|
512
|
+
React.createElement(Field, {
|
|
513
|
+
label: t('appWindow'),
|
|
514
|
+
badges: badgesFor('appWindow'),
|
|
515
|
+
control: React.createElement(Checkbox, { checked: state.appWindow.text === true, disabled: !state.writable, onChange: (v) => props.edit('appWindow', v) }, t('appWindowHint'))
|
|
516
|
+
}),
|
|
458
517
|
// ---- 窗口类型 ----
|
|
459
|
-
React.createElement(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
),
|
|
467
|
-
// ---- 浏览器可执行文件(
|
|
468
|
-
React.createElement(
|
|
469
|
-
id: 'auto-open-web-browser-path',
|
|
518
|
+
React.createElement(Field, {
|
|
519
|
+
label: t('windowKind'),
|
|
520
|
+
badges: badgesFor('windowKind'),
|
|
521
|
+
control: React.createElement(React.Fragment, null,
|
|
522
|
+
React.createElement(Radio, { checked: state.windowKind.text === 'webview2', disabled: !state.writable, value: 'webview2', onChange: (v) => props.edit('windowKind', v) }, t('windowKindWebview2')),
|
|
523
|
+
React.createElement(Radio, { checked: state.windowKind.text === 'browser', disabled: !state.writable, value: 'browser', onChange: (v) => props.edit('windowKind', v) }, t('windowKindBrowser'))
|
|
524
|
+
)
|
|
525
|
+
}),
|
|
526
|
+
// ---- 浏览器可执行文件(输入 + 浏览/测试按钮) ----
|
|
527
|
+
React.createElement(Field, {
|
|
470
528
|
label: t('browserPath'),
|
|
529
|
+
badges: badgesFor('browserPath'),
|
|
471
530
|
hint: t('browserPathHint'),
|
|
472
|
-
overridden: state.browserPath.overridden,
|
|
473
|
-
overriddenLabel: t('overridden'),
|
|
474
|
-
resetLabel: t('reset'),
|
|
475
531
|
invalid: state.browserPath.invalid,
|
|
476
532
|
invalidLabel: t('browserPathInvalid'),
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
533
|
+
control: React.createElement('div', { className: 'aow-row' },
|
|
534
|
+
React.createElement(TextInput, {
|
|
535
|
+
id: 'auto-open-web-browser-path',
|
|
536
|
+
value: state.browserPath.text,
|
|
537
|
+
placeholder: t('browserPathPlaceholder'),
|
|
538
|
+
disabled: browserDisabled,
|
|
539
|
+
invalid: state.browserPath.invalid,
|
|
540
|
+
onChange: (text) => props.edit('browserPath', text)
|
|
541
|
+
}),
|
|
542
|
+
React.createElement(Btn, { disabled: !state.writable || picking, onClick: browse }, picking ? t('browsePicking') : t('browse')),
|
|
543
|
+
React.createElement(Btn, { disabled: testing || state.windowKind.text !== 'browser', onClick: testBrowser }, testing ? t('testRunning') : t('test'))
|
|
485
544
|
),
|
|
486
545
|
footer: testResult !== null
|
|
487
546
|
? React.createElement('p', { className: testResult.ok ? 'aow-test-ok' : 'aow-test-fail', role: 'status' },
|
|
@@ -490,20 +549,22 @@ window.__ModuleLoader__.load({
|
|
|
490
549
|
: null
|
|
491
550
|
}),
|
|
492
551
|
// ---- 窗口关闭时退出 DSH(实验性) ----
|
|
493
|
-
React.createElement(
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
552
|
+
React.createElement(Field, {
|
|
553
|
+
label: t('exitOnWindowClose'),
|
|
554
|
+
badges: React.createElement(FieldBadges, {
|
|
555
|
+
static: t('experimental'),
|
|
556
|
+
overridden: state.exitOnWindowClose.overridden,
|
|
557
|
+
disabled: !state.writable,
|
|
558
|
+
overriddenLabel: t('overridden'),
|
|
559
|
+
resetLabel: t('reset'),
|
|
560
|
+
onReset: () => props.resetField('exitOnWindowClose')
|
|
561
|
+
}),
|
|
562
|
+
control: React.createElement(Checkbox, { checked: state.exitOnWindowClose.text === true, disabled: !state.writable, onChange: (v) => props.edit('exitOnWindowClose', v) }, t('exitOnWindowCloseHint'))
|
|
563
|
+
})
|
|
503
564
|
)
|
|
504
565
|
}
|
|
505
566
|
|
|
506
|
-
// ---- 文案(
|
|
567
|
+
// ---- 文案(locale 机制,zh/en/ja/ko/fr/de/ru) ----
|
|
507
568
|
const NS = 'auto-open-web'
|
|
508
569
|
const en = {
|
|
509
570
|
title: 'Auto-open web',
|
|
@@ -514,7 +575,7 @@ window.__ModuleLoader__.load({
|
|
|
514
575
|
expand: 'Show settings', collapse: 'Hide settings',
|
|
515
576
|
overridden: 'Overridden', reset: 'Reset to default',
|
|
516
577
|
appWindow: 'Independent app window',
|
|
517
|
-
appWindowHint: 'Automatically open an independent app window on start; off opens
|
|
578
|
+
appWindowHint: 'Automatically open an independent app window on start; off behaves like the official core — the GUI opens in the default browser instead',
|
|
518
579
|
windowKind: 'Window kind',
|
|
519
580
|
windowKindWebview2: 'WebView2 host (own process, DSH taskbar icon, exits with DSH; needs Windows + WebView2 runtime)',
|
|
520
581
|
windowKindBrowser: 'Browser app window (dedicated --app instance, isolated from the normal browser)',
|
|
@@ -537,7 +598,7 @@ window.__ModuleLoader__.load({
|
|
|
537
598
|
expand: '展开设置', collapse: '收起设置',
|
|
538
599
|
overridden: '已覆盖', reset: '恢复默认',
|
|
539
600
|
appWindow: '独立应用窗口',
|
|
540
|
-
appWindowHint: '
|
|
601
|
+
appWindowHint: '启动时自动打开独立应用窗口;关闭后与官方相同:改用系统默认浏览器打开 GUI',
|
|
541
602
|
windowKind: '窗口类型',
|
|
542
603
|
windowKindWebview2: 'WebView2 宿主(独立进程,任务栏 DSH 图标,随 DSH 退出;需 Windows + WebView2 运行时)',
|
|
543
604
|
windowKindBrowser: '浏览器应用窗口(--app 专用实例,不与其他浏览器页面共用进程)',
|
|
@@ -560,7 +621,7 @@ window.__ModuleLoader__.load({
|
|
|
560
621
|
expand: '設定を表示', collapse: '設定を隠す',
|
|
561
622
|
overridden: '上書き済み', reset: 'デフォルトに戻す',
|
|
562
623
|
appWindow: '独立アプリウィンドウ',
|
|
563
|
-
appWindowHint: '
|
|
624
|
+
appWindowHint: '起動時に独立アプリウィンドウを自動的に開く;オフの場合は公式と同じく既定ブラウザで GUI を開く',
|
|
564
625
|
windowKind: 'ウィンドウの種類',
|
|
565
626
|
windowKindWebview2: 'WebView2 ホスト(独立プロセス、タスクバーは DSH アイコン、DSH とともに終了;Windows + WebView2 ランタイムが必要)',
|
|
566
627
|
windowKindBrowser: 'ブラウザアプリウィンドウ(専用 --app インスタンス、通常のブラウザとプロセスを共有しない)',
|
|
@@ -583,7 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
583
644
|
expand: '설정 표시', collapse: '설정 숨기기',
|
|
584
645
|
overridden: '재정의됨', reset: '기본값으로 재설정',
|
|
585
646
|
appWindow: '독립 앱 창',
|
|
586
|
-
appWindowHint: '시작 시 독립 앱 창을 자동으로 엽니다. 끄면
|
|
647
|
+
appWindowHint: '시작 시 독립 앱 창을 자동으로 엽니다. 끄면 공식과 동일하게 기본 브라우저로 GUI를 엽니다',
|
|
587
648
|
windowKind: '창 종류',
|
|
588
649
|
windowKindWebview2: 'WebView2 호스트(독립 프로세스, 작업 표시줄 DSH 아이콘, DSH와 함께 종료; Windows + WebView2 런타임 필요)',
|
|
589
650
|
windowKindBrowser: '브라우저 앱 창(전용 --app 인스턴스, 일반 브라우저와 프로세스 공유 안 함)',
|
|
@@ -606,7 +667,7 @@ window.__ModuleLoader__.load({
|
|
|
606
667
|
expand: 'Afficher les paramètres', collapse: 'Masquer les paramètres',
|
|
607
668
|
overridden: 'Remplacé', reset: 'Rétablir la valeur par défaut',
|
|
608
669
|
appWindow: "Fenêtre d'application indépendante",
|
|
609
|
-
appWindowHint: "Ouvre automatiquement une fenêtre d'application indépendante au démarrage; désactivé
|
|
670
|
+
appWindowHint: "Ouvre automatiquement une fenêtre d'application indépendante au démarrage; désactivé = comme le cœur officiel, ouverture dans le navigateur par défaut",
|
|
610
671
|
windowKind: 'Type de fenêtre',
|
|
611
672
|
windowKindWebview2: 'Hôte WebView2 (processus propre, icône DSH dans la barre des tâches, se ferme avec DSH; nécessite Windows + runtime WebView2)',
|
|
612
673
|
windowKindBrowser: 'Fenêtre de navigateur (instance --app dédiée, isolée du navigateur normal)',
|
|
@@ -629,7 +690,7 @@ window.__ModuleLoader__.load({
|
|
|
629
690
|
expand: 'Einstellungen anzeigen', collapse: 'Einstellungen ausblenden',
|
|
630
691
|
overridden: 'Überschrieben', reset: 'Standard wiederherstellen',
|
|
631
692
|
appWindow: 'Eigenständiges App-Fenster',
|
|
632
|
-
appWindowHint: 'Beim Start automatisch ein eigenständiges App-Fenster öffnen; aus =
|
|
693
|
+
appWindowHint: 'Beim Start automatisch ein eigenständiges App-Fenster öffnen; aus = wie offiziell, Öffnen der GUI im Standardbrowser',
|
|
633
694
|
windowKind: 'Fenstertyp',
|
|
634
695
|
windowKindWebview2: 'WebView2-Host (eigener Prozess, DSH-Symbol in der Taskleiste, wird mit DSH beendet; benötigt Windows + WebView2-Runtime)',
|
|
635
696
|
windowKindBrowser: 'Browser-App-Fenster (dedizierte --app-Instanz, getrennt vom normalen Browser)',
|
|
@@ -652,7 +713,7 @@ window.__ModuleLoader__.load({
|
|
|
652
713
|
expand: 'Показать настройки', collapse: 'Скрыть настройки',
|
|
653
714
|
overridden: 'Переопределено', reset: 'Вернуть по умолчанию',
|
|
654
715
|
appWindow: 'Независимое окно приложения',
|
|
655
|
-
appWindowHint: 'Автоматически открывать независимое окно приложения при запуске; выкл. —
|
|
716
|
+
appWindowHint: 'Автоматически открывать независимое окно приложения при запуске; выкл. — как в официальной версии, открытие GUI в браузере по умолчанию',
|
|
656
717
|
windowKind: 'Тип окна',
|
|
657
718
|
windowKindWebview2: 'Хост WebView2 (собственный процесс, значок DSH на панели задач, закрывается вместе с DSH; требуется Windows + среда WebView2)',
|
|
658
719
|
windowKindBrowser: 'Окно браузера (выделенный экземпляр --app, изолирован от обычного браузера)',
|
|
@@ -668,7 +729,7 @@ window.__ModuleLoader__.load({
|
|
|
668
729
|
}
|
|
669
730
|
|
|
670
731
|
function apply(ctx) {
|
|
671
|
-
// 文案(locale
|
|
732
|
+
// 文案(locale 机制,跟随界面语言)
|
|
672
733
|
ctx.effect(() => ctx.locale.register(NS, { zh, en, ja, ko, fr, de, ru }), 'auto-open-web: card dictionary')
|
|
673
734
|
// 数据通道:settingsScope(官方 settings 域)
|
|
674
735
|
const scope = ctx.settingsScope.bind({ namespace: 'auto-open-web' })
|
|
@@ -682,7 +743,7 @@ window.__ModuleLoader__.load({
|
|
|
682
743
|
)
|
|
683
744
|
}
|
|
684
745
|
|
|
685
|
-
// 代码级服务依赖(cordis)
|
|
746
|
+
// 代码级服务依赖(cordis):数据/机制服务,不含任何 UI 包
|
|
686
747
|
var clientInject = ['slots', 'locale', 'connection', 'remote', 'settingsScope']
|
|
687
748
|
|
|
688
749
|
exports.apply = apply
|