@nsnanocat/preference-panes 1.0.0 → 1.1.1

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.
@@ -147,26 +147,8 @@ class ActionMenu {
147
147
  }
148
148
 
149
149
  /**
150
- * 统一解析模块页的资源地址:Header 优先于查询参数,再使用模块约定。
151
- * Resolve module resource locations: headers override query parameters and module conventions.
152
- * @param {URL} url 已解析的页面请求地址 / Parsed page request URL.
153
- * @param {Record<string, string | undefined>} [headers] 请求头,名称不区分大小写 / Case-insensitive request headers.
154
- * @returns {{url: string, module: string, json: string, css: string}} 页面上下文与两个资源输入 / Page context and two resource inputs.
155
- */
156
- function pageInputs(url, headers = {}) {
157
- const match = /^\/settings\/([a-zA-Z0-9_-]+)\/?$/.exec(url.pathname);
158
- if (!match) throw new TypeError("Open a concrete module URL");
159
- const module = match[1];
160
- const values = Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value]));
161
- const json = values["x-preferencepanes-json"] ?? url.searchParams.get("json") ?? `/configs/${module}`;
162
- const css = values["x-preferencepanes-css"] ?? url.searchParams.get("css") ?? "";
163
- if (!json.trim()) throw new TypeError("JSON resource URL is required");
164
- return { url: url.href, module, json, css };
165
- }
166
-
167
- /**
168
- * 模块文档容器:原始 HTML 不改写,请求上下文随 iframe 元素传递。
169
- * Module document container: preserve HTML verbatim and carry request context on the iframe element.
150
+ * 模块文档容器:原始 HTML 不改写,只向 iframe 标记模块身份。
151
+ * Module document container: preserve HTML verbatim and mark only the module identity on the iframe.
170
152
  */
171
153
  class ModuleFrame extends EventTarget {
172
154
  #url;
@@ -188,23 +170,25 @@ class ModuleFrame extends EventTarget {
188
170
  };
189
171
 
190
172
  /**
191
- * 建立 iframe 与请求输入;调用方挂载 element 后调用 load。
192
- * Create the iframe and request inputs; callers mount element and then call load.
173
+ * 建立 iframe;调用方挂载 element 后调用 load。
174
+ * Create the iframe; callers mount element and then call load.
193
175
  * @param {string | URL} url 模块请求地址 / Module request URL.
194
- * @param {RequestInit} [options] 原生请求头和取消信号 / Native headers and cancellation signal.
176
+ * @param {{signal?: AbortSignal}} [options] 外部取消信号 / External cancellation signal.
195
177
  */
196
178
  constructor(url, options = {}) {
197
179
  super();
198
180
  this.#url = new URL(url, document.baseURI);
199
- this.#options = { ...options, headers: new Headers(options.headers) };
200
- const inputs = pageInputs(this.#url, Object.fromEntries(this.#options.headers));
181
+ const match = /^\/settings\/([a-zA-Z0-9_-]+)\/?$/.exec(this.#url.pathname);
182
+ if (!match) throw new TypeError("Open a concrete module URL");
183
+ this.#options = options;
201
184
  this.element = document.createElement("iframe");
202
- this.element.title = `${inputs.module} 设置`;
203
- this.element.dataset.preferencePanes = JSON.stringify(inputs);
185
+ this.element.title = `${match[1]} 设置`;
186
+ this.element.dataset.preferencePanes = "true";
187
+ this.element.dataset.preferencePanesModule = match[1];
204
188
  this.element.addEventListener("preferencepanes:change", this.#change);
205
189
  this.element.addEventListener("preferencepanes:confirm", this.#confirmation);
206
190
  this.element.addEventListener("preferencepanes:notice", this.#notice);
207
- this.#state = { title: inputs.module, module: inputs.module, busy: false, canGoBack: true, actions: [] };
191
+ this.#state = { title: match[1], module: match[1], busy: false, canGoBack: true, actions: [] };
208
192
  options.signal?.addEventListener("abort", this.#abort, { once: true });
209
193
  }
210
194
 
@@ -225,7 +209,7 @@ class ModuleFrame extends EventTarget {
225
209
  if (this.#options.signal?.aborted) this.destroy();
226
210
  const timer = setTimeout(() => this.#controller.abort(), 10000);
227
211
  try {
228
- const response = await fetch(this.#url, { cache: "no-store", credentials: "omit", ...this.#options, signal: this.#controller.signal });
212
+ const response = await fetch(this.#url, { cache: "no-store", credentials: "omit", signal: this.#controller.signal });
229
213
  if (response.status !== 200) throw new Error(`HTTP ${response.status}`);
230
214
  const html = await response.text();
231
215
  this.#controller.signal.throwIfAborted();
@@ -275,7 +259,6 @@ class ModuleFrame extends EventTarget {
275
259
  * @typedef {object} ModuleProbeOptions
276
260
  * @property {typeof globalThis.fetch} [fetch] 可注入的 fetch / Injectable fetch.
277
261
  * @property {AbortSignal} [signal] 外部取消信号 / External cancellation signal.
278
- * @property {string} [json] BoxJS JSON 来源,将随探测请求头传递 / BoxJS JSON source sent in the probe header.
279
262
  * @property {number} [timeout] 超时毫秒数,默认 3500 / Timeout in milliseconds, defaults to 3500.
280
263
  */
281
264
 
@@ -286,14 +269,14 @@ class ModuleFrame extends EventTarget {
286
269
  * @param {ModuleProbeOptions} [options] 请求选项 / Request options.
287
270
  * @returns {Promise<Response>} 原始 HTTP 响应,可直接读取 status 和响应头 / Native HTTP response; read status and headers directly.
288
271
  */
289
- async function probeModule(url, { fetch: request = globalThis.fetch, json, signal, timeout = 3500 } = {}) {
272
+ async function probeModule(url, { fetch: request = globalThis.fetch, signal, timeout = 3500 } = {}) {
290
273
  const controller = new AbortController();
291
274
  const abort = () => controller.abort();
292
275
  if (signal?.aborted) abort();
293
276
  signal?.addEventListener("abort", abort, { once: true });
294
277
  const timer = setTimeout(() => controller.abort(), timeout);
295
278
  try {
296
- return await request(url, { method: "HEAD", cache: "no-store", credentials: "omit", signal: controller.signal, headers: json ? { "X-PreferencePanes-JSON": json } : undefined });
279
+ return await request(url, { method: "HEAD", cache: "no-store", credentials: "omit", signal: controller.signal });
297
280
  } finally {
298
281
  clearTimeout(timer);
299
282
  signal?.removeEventListener("abort", abort);