@cychien/ezdesign 0.8.1 → 0.9.2
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.md +166 -37
- package/dist/announcements/template-ERNKAKI5.svg +33 -0
- package/dist/cli.mjs +7623 -3145
- package/dist/constants.d.ts +38 -8
- package/dist/events-worker.js +77 -0
- package/dist/extension/g/0.9.2-d9aee83dae/dialog.css +1 -0
- package/dist/extension/g/0.9.2-d9aee83dae/dialog.html +13 -0
- package/dist/extension/g/0.9.2-d9aee83dae/dialog.js +1 -0
- package/dist/extension/g/0.9.2-d9aee83dae/icon-128.png +0 -0
- package/dist/extension/g/0.9.2-d9aee83dae/icon-16.png +0 -0
- package/dist/extension/g/0.9.2-d9aee83dae/icon-32.png +0 -0
- package/dist/extension/g/0.9.2-d9aee83dae/icon-48.png +0 -0
- package/dist/extension/g/0.9.2-d9aee83dae/media.html +9 -0
- package/dist/extension/g/0.9.2-d9aee83dae/media.js +1 -0
- package/dist/extension/g/0.9.2-d9aee83dae/page.js +39 -0
- package/dist/extension/g/0.9.2-d9aee83dae/setup.css +1 -0
- package/dist/extension/g/0.9.2-d9aee83dae/setup.html +17 -0
- package/dist/extension/g/0.9.2-d9aee83dae/setup.js +1 -0
- package/dist/extension/g/0.9.2-d9aee83dae/worker.js +57 -0
- package/dist/extension/manifest.json +57 -0
- package/dist/native-host.mjs +20613 -0
- package/dist/overlay.css +0 -43
- package/dist/overlay.js +284 -89
- package/dist/shell.css +1602 -21
- package/dist/shell.js +4389 -736
- package/dist/vite.mjs +6 -0
- package/package.json +8 -5
- package/skills/ezdesign/SKILL.md +24 -67
- package/skills/ezdesign/reference/start.md +3 -1
package/dist/overlay.js
CHANGED
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
5
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
6
|
|
|
7
|
-
// node_modules/.pnpm/@hugeicons+core-free-icons@4.
|
|
7
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/Add01Icon.js
|
|
8
8
|
var Add01Icon = [
|
|
9
9
|
["path", { d: "M12.001 5.00003V19.002", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
10
10
|
["path", { d: "M19.002 12.002L4.99998 12.002", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "1" }]
|
|
11
11
|
];
|
|
12
|
-
var Add01Icon_default = Add01Icon;
|
|
13
12
|
|
|
14
|
-
// node_modules/.pnpm/@hugeicons+core-free-icons@4.
|
|
13
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/AlignSelectionIcon.js
|
|
15
14
|
var AlignSelectionIcon = [
|
|
16
15
|
["path", { d: "M20 6V18M18 4H6M18 20H6M4 18V6", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
17
16
|
["path", { d: "M22 4C22 5.10457 21.1046 6 20 6C18.8954 6 18 5.10457 18 4C18 2.89543 18.8954 2 20 2C21.1046 2 22 2.89543 22 4Z", stroke: "currentColor", strokeWidth: "1.5", key: "1" }],
|
|
@@ -19,35 +18,40 @@
|
|
|
19
18
|
["path", { d: "M22 20C22 21.1046 21.1046 22 20 22C18.8954 22 18 21.1046 18 20C18 18.8954 18.8954 18 20 18C21.1046 18 22 18.8954 22 20Z", stroke: "currentColor", strokeWidth: "1.5", key: "3" }],
|
|
20
19
|
["path", { d: "M6 20C6 21.1046 5.10457 22 4 22C2.89543 22 2 21.1046 2 20C2 18.8954 2.89543 18 4 18C5.10457 18 6 18.8954 6 20Z", stroke: "currentColor", strokeWidth: "1.5", key: "4" }]
|
|
21
20
|
];
|
|
22
|
-
var AlignSelectionIcon_default = AlignSelectionIcon;
|
|
23
21
|
|
|
24
|
-
// node_modules/.pnpm/@hugeicons+core-free-icons@4.
|
|
22
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/TextSelectIcon.js
|
|
25
23
|
var TextSelectIcon = [
|
|
26
24
|
["path", { d: "M9.99877 2.5C9.45899 2.50516 8.96002 2.51488 8.49784 2.53315M14.0012 2.5C14.541 2.50516 15.04 2.51488 15.5022 2.53315M19.0043 3.13088C19.43 3.32055 19.7943 3.56673 20.1138 3.88624C20.4333 4.20575 20.6794 4.56995 20.8691 4.99568M3.13088 4.99568C3.32056 4.56995 3.56673 4.20575 3.88624 3.88624C4.20575 3.56673 4.56995 3.32055 4.99568 3.13088M21.5 9.99877C21.4948 9.45899 21.4851 8.96002 21.4669 8.49784M21.5 14.0012C21.4948 14.5409 21.4851 15.0399 21.4669 15.5021M20.8691 19.0043C20.6794 19.43 20.4333 19.7943 20.1138 20.1138C19.7943 20.4333 19.43 20.6794 19.0043 20.8691M15.5022 21.4668C15.04 21.4851 14.541 21.4948 14.0012 21.5M9.99877 21.5C9.45898 21.4948 8.96 21.4851 8.49781 21.4668M4.99568 20.8691C4.56995 20.6794 4.20575 20.4333 3.88624 20.1138C3.56673 19.7943 3.32056 19.43 3.13088 19.0043M2.5 14.0012C2.50516 14.5409 2.51488 15.0399 2.53315 15.5021M2.5 9.99884C2.50516 9.45904 2.51488 8.96004 2.53315 8.49784", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
27
25
|
["path", { d: "M7 8H15M7 12H17M7 16H13", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "1" }]
|
|
28
26
|
];
|
|
29
|
-
var TextSelectIcon_default = TextSelectIcon;
|
|
30
27
|
|
|
31
|
-
// node_modules/.pnpm/@hugeicons+core-free-icons@4.
|
|
28
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/MagicWand01Icon.js
|
|
32
29
|
var MagicWand01Icon = [
|
|
33
30
|
["path", { d: "M13.9258 12.7775L11.7775 10.6292C11.4847 10.3364 11.3383 10.19 11.1803 10.1117C10.8798 9.96277 10.527 9.96277 10.2264 10.1117C10.0685 10.19 9.92207 10.3364 9.62923 10.6292C9.33638 10.9221 9.18996 11.0685 9.11169 11.2264C8.96277 11.527 8.96277 11.8798 9.11169 12.1803C9.18996 12.3383 9.33638 12.4847 9.62923 12.7775L11.7775 14.9258M13.9258 12.7775L20.3708 19.2225C20.6636 19.5153 20.81 19.6617 20.8883 19.8197C21.0372 20.1202 21.0372 20.473 20.8883 20.7736C20.81 20.9315 20.6636 21.0779 20.3708 21.3708C20.0779 21.6636 19.9315 21.81 19.7736 21.8883C19.473 22.0372 19.1202 22.0372 18.8197 21.8883C18.6617 21.81 18.5153 21.6636 18.2225 21.3708L11.7775 14.9258M13.9258 12.7775L11.7775 14.9258", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
34
31
|
["path", { d: "M17 2L17.2948 2.7966C17.6813 3.84117 17.8746 4.36345 18.2556 4.74445C18.6366 5.12545 19.1588 5.31871 20.2034 5.70523L21 6L20.2034 6.29477C19.1588 6.68129 18.6366 6.87456 18.2556 7.25555C17.8746 7.63655 17.6813 8.15883 17.2948 9.2034L17 10L16.7052 9.2034C16.3187 8.15884 16.1254 7.63655 15.7444 7.25555C15.3634 6.87455 14.8412 6.68129 13.7966 6.29477L13 6L13.7966 5.70523C14.8412 5.31871 15.3634 5.12545 15.7444 4.74445C16.1254 4.36345 16.3187 3.84117 16.7052 2.7966L17 2Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.5", key: "1" }],
|
|
35
32
|
["path", { d: "M6 4L6.22108 4.59745C6.51097 5.38087 6.65592 5.77259 6.94167 6.05834C7.22741 6.34408 7.61913 6.48903 8.40255 6.77892L9 7L8.40255 7.22108C7.61913 7.51097 7.22741 7.65592 6.94166 7.94167C6.65592 8.22741 6.51097 8.61913 6.22108 9.40255L6 10L5.77892 9.40255C5.48903 8.61913 5.34408 8.22741 5.05833 7.94167C4.77259 7.65592 4.38087 7.51097 3.59745 7.22108L3 7L3.59745 6.77892C4.38087 6.48903 4.77259 6.34408 5.05833 6.05833C5.34408 5.77259 5.48903 5.38087 5.77892 4.59745L6 4Z", stroke: "currentColor", strokeLinejoin: "round", strokeWidth: "1.5", key: "2" }]
|
|
36
33
|
];
|
|
37
|
-
var MagicWand01Icon_default = MagicWand01Icon;
|
|
38
34
|
|
|
39
|
-
// node_modules/.pnpm/@hugeicons+core-free-icons@4.
|
|
35
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/Album02Icon.js
|
|
36
|
+
var Album02Icon = [
|
|
37
|
+
["path", { d: "M17.5 5.73041V6.29128M17.7801 6.00085H17.25M18 6.00085C18 6.277 17.7761 6.50085 17.5 6.50085C17.2239 6.50085 17 6.277 17 6.00085C17 5.72471 17.2239 5.50085 17.5 5.50085C17.7761 5.50085 18 5.72471 18 6.00085Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
38
|
+
["path", { d: "M9.5 7.99945C9.5 5.17102 9.5 3.75681 10.3787 2.87813C11.2574 1.99945 12.6716 1.99945 15.5 1.99945C18.3284 1.99945 19.7426 1.99945 20.6213 2.87813C21.5 3.75681 21.5 5.17102 21.5 7.99945V11.9995C21.5 14.8279 21.5 16.2421 20.6213 17.1208C19.7426 17.9995 18.3284 17.9995 15.5 17.9995C12.6716 17.9995 11.2574 17.9995 10.3787 17.1208C9.5 16.2421 9.5 14.8279 9.5 11.9995V7.99945Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "1" }],
|
|
39
|
+
["path", { d: "M6.62279 5.99878C4.49094 6.58122 3.36407 6.978 2.81621 7.92692C2.19489 9.00308 2.56092 10.3691 3.29297 13.1012L4.32825 16.9649C5.0603 19.6969 5.42632 21.0629 6.50248 21.6843C7.57864 22.3056 8.94467 21.9396 11.6767 21.2075C12.1593 21.0782 12.5992 20.9603 13 20.8479", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "2" }],
|
|
40
|
+
["path", { d: "M9.5 13.9995L12.8693 10.6301C13.2731 10.2263 13.8208 9.99945 14.3919 9.99945C15.0873 9.99945 15.7399 10.3353 16.1441 10.9011L20.5 16.9995", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "3" }]
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// node_modules/.pnpm/@hugeicons+core-free-icons@4.3.5/node_modules/@hugeicons/core-free-icons/dist/esm/File02Icon.js
|
|
40
44
|
var File02Icon = [
|
|
41
45
|
["path", { d: "M8 17H16", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "0" }],
|
|
42
46
|
["path", { d: "M8 13H12", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "1" }],
|
|
43
47
|
["path", { d: "M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", key: "2" }]
|
|
44
48
|
];
|
|
45
|
-
var File02Icon_default = File02Icon;
|
|
46
49
|
|
|
47
50
|
// src/client/draft.ts
|
|
48
51
|
var NBSP = "\xA0";
|
|
49
52
|
var refMarker = (n) => `[ref ${n}]`;
|
|
50
53
|
var refChipText = (n, chosen = false) => `${chosen ? "\u63A2\u7D22\u6A23\u5F0F" : "\u9078\u53D6\u5143\u7D20"} ${n}`;
|
|
54
|
+
var pickChipText = (n) => `\u9078\u53D6\u7D20\u6750 ${n}`;
|
|
51
55
|
var fileMarker = (n) => `[file ${n}]`;
|
|
52
56
|
var skillMarker = (n) => `[skill ${n}]`;
|
|
53
57
|
function draftText(body) {
|
|
@@ -59,6 +63,7 @@
|
|
|
59
63
|
else if (node.t === "ref" && node.anchor) out.push(refMarker(node.n));
|
|
60
64
|
else if (node.t === "file" && node.id) out.push(fileMarker(++file));
|
|
61
65
|
else if (node.t === "skill") out.push(skillMarker(++skill));
|
|
66
|
+
else if (node.t === "pick") out.push(node.files.map(() => fileMarker(++file)).join(" "));
|
|
62
67
|
}
|
|
63
68
|
return out.join("").replaceAll(NBSP, " ").trim();
|
|
64
69
|
}
|
|
@@ -87,7 +92,7 @@
|
|
|
87
92
|
return max + 1;
|
|
88
93
|
}
|
|
89
94
|
function draftFileIds(body) {
|
|
90
|
-
return body.flatMap((n) => n.t === "file" && n.id ? [n.id] : []);
|
|
95
|
+
return body.flatMap((n) => n.t === "file" && n.id ? [n.id] : n.t === "pick" ? n.files.map((f) => f.id) : []);
|
|
91
96
|
}
|
|
92
97
|
function draftPendingNames(body) {
|
|
93
98
|
return body.flatMap((n) => n.t === "file" && !n.id ? [n.name] : []);
|
|
@@ -142,6 +147,7 @@
|
|
|
142
147
|
// src/client/slash.ts
|
|
143
148
|
var MAX_QUERY = 24;
|
|
144
149
|
var BREAK = /[\s ]/;
|
|
150
|
+
var menuCount = 0;
|
|
145
151
|
function detectSlash(before, trigger = "/") {
|
|
146
152
|
const start = before.lastIndexOf(trigger);
|
|
147
153
|
if (start === -1) return null;
|
|
@@ -168,6 +174,7 @@
|
|
|
168
174
|
}) {
|
|
169
175
|
const doc = editable.ownerDocument;
|
|
170
176
|
const view = doc.defaultView;
|
|
177
|
+
const listId = `ez-slash-${++menuCount}`;
|
|
171
178
|
let menu = null;
|
|
172
179
|
let trigger = null;
|
|
173
180
|
let shown = [];
|
|
@@ -211,6 +218,7 @@
|
|
|
211
218
|
item.toggleAttribute("data-active", i === active);
|
|
212
219
|
item.setAttribute("aria-selected", String(i === active));
|
|
213
220
|
});
|
|
221
|
+
editable.setAttribute("aria-activedescendant", `${listId}-${active}`);
|
|
214
222
|
}
|
|
215
223
|
function render() {
|
|
216
224
|
if (!menu) return;
|
|
@@ -218,10 +226,13 @@
|
|
|
218
226
|
const headEl = mk("div", "ez-slash-head");
|
|
219
227
|
headEl.textContent = title;
|
|
220
228
|
const list = mk("div", "ez-slash-list");
|
|
229
|
+
list.id = listId;
|
|
221
230
|
list.setAttribute("role", "listbox");
|
|
231
|
+
list.setAttribute("aria-label", title);
|
|
222
232
|
menu.append(headEl, list);
|
|
223
233
|
shown.forEach((command, i) => {
|
|
224
234
|
const item = mk("div", "ez-slash-item");
|
|
235
|
+
item.id = `${listId}-${i}`;
|
|
225
236
|
item.setAttribute("role", "option");
|
|
226
237
|
const label = mk("span", "ez-slash-label");
|
|
227
238
|
label.textContent = command.label;
|
|
@@ -255,6 +266,7 @@
|
|
|
255
266
|
function open() {
|
|
256
267
|
menu = mk("div", "ez-slash-menu");
|
|
257
268
|
doc.body.appendChild(menu);
|
|
269
|
+
editable.setAttribute("aria-controls", listId);
|
|
258
270
|
doc.addEventListener("selectionchange", onSelectionChange);
|
|
259
271
|
editable.addEventListener("blur", onBlur);
|
|
260
272
|
}
|
|
@@ -263,6 +275,8 @@
|
|
|
263
275
|
menu.remove();
|
|
264
276
|
menu = null;
|
|
265
277
|
trigger = null;
|
|
278
|
+
editable.removeAttribute("aria-controls");
|
|
279
|
+
editable.removeAttribute("aria-activedescendant");
|
|
266
280
|
doc.removeEventListener("selectionchange", onSelectionChange);
|
|
267
281
|
editable.removeEventListener("blur", onBlur);
|
|
268
282
|
return true;
|
|
@@ -351,17 +365,43 @@
|
|
|
351
365
|
|
|
352
366
|
// src/client/attach.ts
|
|
353
367
|
var MAX_BYTES = 8 * 1024 * 1024;
|
|
368
|
+
function directAttachments(api) {
|
|
369
|
+
return {
|
|
370
|
+
async upload(file) {
|
|
371
|
+
const res = await fetch(`${api}/attachments`, {
|
|
372
|
+
method: "POST",
|
|
373
|
+
headers: {
|
|
374
|
+
"content-type": file.type || "application/octet-stream",
|
|
375
|
+
// A filename is free to hold bytes no header may carry.
|
|
376
|
+
"x-ez-name": encodeURIComponent(file.name || "image.png")
|
|
377
|
+
},
|
|
378
|
+
body: file
|
|
379
|
+
});
|
|
380
|
+
if (!res.ok) {
|
|
381
|
+
const body = await res.json().catch(() => null);
|
|
382
|
+
throw new Error(body?.error ?? `HTTP ${res.status}`);
|
|
383
|
+
}
|
|
384
|
+
return await res.json();
|
|
385
|
+
},
|
|
386
|
+
discard(id) {
|
|
387
|
+
fetch(`${api}/attachments/${id}`, { method: "DELETE" }).catch(() => {
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
354
392
|
var CHIP_ATTR = "data-ez-chip";
|
|
355
393
|
var REF_ATTR = "data-ez-ref";
|
|
356
394
|
var SKILL_ATTR = "data-ez-skill";
|
|
395
|
+
var PICK_ATTR = "data-ez-pick";
|
|
357
396
|
function attachify({
|
|
358
|
-
|
|
397
|
+
attachments,
|
|
359
398
|
mk,
|
|
360
399
|
className,
|
|
361
400
|
placeholder,
|
|
362
401
|
onChange,
|
|
363
402
|
commands,
|
|
364
|
-
skills
|
|
403
|
+
skills,
|
|
404
|
+
chooseLibrary
|
|
365
405
|
}) {
|
|
366
406
|
const editable = mk("div", className);
|
|
367
407
|
editable.setAttribute("contenteditable", "plaintext-only");
|
|
@@ -391,9 +431,19 @@
|
|
|
391
431
|
label: "File",
|
|
392
432
|
hint: "\u9644\u52A0\u6A94\u6848",
|
|
393
433
|
keywords: ["file", "attach", "upload", "\u6A94\u6848", "\u9644\u4EF6", "\u5716\u7247"],
|
|
394
|
-
icon:
|
|
434
|
+
icon: File02Icon,
|
|
395
435
|
run: () => picker.click()
|
|
396
436
|
},
|
|
437
|
+
...chooseLibrary ? [
|
|
438
|
+
{
|
|
439
|
+
id: "library",
|
|
440
|
+
label: "Library",
|
|
441
|
+
hint: "\u5F9E\u7D20\u6750\u5EAB\u9078\u64C7",
|
|
442
|
+
keywords: ["library", "reference", "asset", "inspiration", "\u7D20\u6750", "\u7D20\u6750\u5EAB", "\u53C3\u8003", "\u9748\u611F"],
|
|
443
|
+
icon: Album02Icon,
|
|
444
|
+
run: () => void addFromLibrary(chooseLibrary)
|
|
445
|
+
}
|
|
446
|
+
] : [],
|
|
397
447
|
...commands ?? []
|
|
398
448
|
]
|
|
399
449
|
});
|
|
@@ -406,7 +456,6 @@
|
|
|
406
456
|
});
|
|
407
457
|
const uploading = /* @__PURE__ */ new Set();
|
|
408
458
|
let errorTimer = 0;
|
|
409
|
-
const chips = () => [...editable.querySelectorAll(`[${CHIP_ATTR}]`)];
|
|
410
459
|
function showError(message) {
|
|
411
460
|
error.textContent = message;
|
|
412
461
|
error.hidden = false;
|
|
@@ -416,16 +465,21 @@
|
|
|
416
465
|
}, 6e3);
|
|
417
466
|
}
|
|
418
467
|
function paintEmpty() {
|
|
419
|
-
const empty = !editable.textContent?.trim() &&
|
|
468
|
+
const empty = !editable.textContent?.trim() && !editable.querySelector(".ez-chip");
|
|
420
469
|
editable.toggleAttribute("data-empty", empty);
|
|
421
470
|
}
|
|
471
|
+
function paintPicks() {
|
|
472
|
+
editable.querySelectorAll(`[${PICK_ATTR}] .ez-chip-name`).forEach((name, i) => {
|
|
473
|
+
name.textContent = pickChipText(i + 1);
|
|
474
|
+
});
|
|
475
|
+
}
|
|
422
476
|
function changed() {
|
|
423
477
|
paintEmpty();
|
|
478
|
+
paintPicks();
|
|
424
479
|
onChange?.();
|
|
425
480
|
}
|
|
426
481
|
function del(id) {
|
|
427
|
-
|
|
428
|
-
});
|
|
482
|
+
attachments.discard(id);
|
|
429
483
|
}
|
|
430
484
|
function makeChip(name, attr, value, glyph) {
|
|
431
485
|
const chip = mk("span", "ez-chip");
|
|
@@ -439,19 +493,24 @@
|
|
|
439
493
|
if (!value) chip.classList.add("ez-chip-pending");
|
|
440
494
|
return chip;
|
|
441
495
|
}
|
|
442
|
-
const fileChip = (name, id = "") => makeChip(name, CHIP_ATTR, id,
|
|
496
|
+
const fileChip = (name, id = "") => makeChip(name, CHIP_ATTR, id, File02Icon);
|
|
443
497
|
const refChip = (ref, placeholder2) => {
|
|
444
498
|
const chip = makeChip(
|
|
445
499
|
ref ? refChipText(ref.n, !!ref.variant) : placeholder2,
|
|
446
500
|
REF_ATTR,
|
|
447
501
|
ref ? JSON.stringify(ref) : "",
|
|
448
|
-
ref?.variant ?
|
|
502
|
+
ref?.variant ? MagicWand01Icon : AlignSelectionIcon
|
|
449
503
|
);
|
|
450
504
|
if (ref?.variant) chip.classList.add("ez-chip-chosen");
|
|
451
505
|
const title = ref?.variant ? [ref.variant.name, ref.label].filter(Boolean).join(" \xB7 ") : ref?.label ?? "";
|
|
452
506
|
if (title) chip.title = title;
|
|
453
507
|
return chip;
|
|
454
508
|
};
|
|
509
|
+
const pickChip = (files) => {
|
|
510
|
+
const chip = makeChip("", PICK_ATTR, JSON.stringify(files), Album02Icon);
|
|
511
|
+
chip.title = files.map((f) => f.name).join("\n");
|
|
512
|
+
return chip;
|
|
513
|
+
};
|
|
455
514
|
const skillChip = (name) => makeChip(`$${name}`, SKILL_ATTR, name, null);
|
|
456
515
|
const pendingRef = () => editable.querySelector(`[${REF_ATTR}=""]`);
|
|
457
516
|
function placeCaretAfter(node) {
|
|
@@ -489,20 +548,7 @@
|
|
|
489
548
|
}
|
|
490
549
|
async function upload(chip, file) {
|
|
491
550
|
try {
|
|
492
|
-
const
|
|
493
|
-
method: "POST",
|
|
494
|
-
headers: {
|
|
495
|
-
"content-type": file.type || "application/octet-stream",
|
|
496
|
-
// A filename is free to hold bytes no header may carry.
|
|
497
|
-
"x-ez-name": encodeURIComponent(file.name || "image.png")
|
|
498
|
-
},
|
|
499
|
-
body: file
|
|
500
|
-
});
|
|
501
|
-
if (!res.ok) {
|
|
502
|
-
const body = await res.json().catch(() => null);
|
|
503
|
-
throw new Error(body?.error ?? `HTTP ${res.status}`);
|
|
504
|
-
}
|
|
505
|
-
const saved = await res.json();
|
|
551
|
+
const saved = await attachments.upload(file);
|
|
506
552
|
if (!editable.contains(chip)) {
|
|
507
553
|
del(saved.id);
|
|
508
554
|
return;
|
|
@@ -518,6 +564,26 @@
|
|
|
518
564
|
changed();
|
|
519
565
|
}
|
|
520
566
|
}
|
|
567
|
+
async function addFromLibrary(choose) {
|
|
568
|
+
const selection = document.getSelection();
|
|
569
|
+
const live = selection?.rangeCount ? selection.getRangeAt(0) : null;
|
|
570
|
+
const spot = live && editable.contains(live.commonAncestorContainer) ? live.cloneRange() : null;
|
|
571
|
+
let files;
|
|
572
|
+
try {
|
|
573
|
+
files = await choose();
|
|
574
|
+
} catch (err) {
|
|
575
|
+
showError(`\u6C92\u9644\u4E0A\u7D20\u6750\uFF1A${err.message}`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
editable.focus();
|
|
579
|
+
if (spot && editable.contains(spot.commonAncestorContainer)) {
|
|
580
|
+
selection?.removeAllRanges();
|
|
581
|
+
selection?.addRange(spot);
|
|
582
|
+
}
|
|
583
|
+
if (!files.length) return;
|
|
584
|
+
insertAtCaret(pickChip(files));
|
|
585
|
+
changed();
|
|
586
|
+
}
|
|
521
587
|
function take(list) {
|
|
522
588
|
return list ? [...list] : [];
|
|
523
589
|
}
|
|
@@ -566,6 +632,7 @@
|
|
|
566
632
|
if (node.t === "text") editable.appendChild(document.createTextNode(node.v));
|
|
567
633
|
else if (node.t === "file") editable.appendChild(fileChip(node.name, node.id));
|
|
568
634
|
else if (node.t === "skill") editable.appendChild(skillChip(node.name));
|
|
635
|
+
else if (node.t === "pick") editable.appendChild(pickChip(node.files));
|
|
569
636
|
else {
|
|
570
637
|
const ref = node.anchor ? {
|
|
571
638
|
n: node.n,
|
|
@@ -590,7 +657,7 @@
|
|
|
590
657
|
e.stopPropagation();
|
|
591
658
|
for (const file of files) add(file);
|
|
592
659
|
});
|
|
593
|
-
const isChipNode = (node) => node instanceof HTMLElement && (node.hasAttribute(CHIP_ATTR) || node.hasAttribute(REF_ATTR) || node.hasAttribute(SKILL_ATTR));
|
|
660
|
+
const isChipNode = (node) => node instanceof HTMLElement && (node.hasAttribute(CHIP_ATTR) || node.hasAttribute(REF_ATTR) || node.hasAttribute(SKILL_ATTR) || node.hasAttribute(PICK_ATTR));
|
|
594
661
|
editable.addEventListener("beforeinput", (e) => {
|
|
595
662
|
if (e.inputType !== "deleteContentBackward") return;
|
|
596
663
|
const selection = document.getSelection();
|
|
@@ -673,7 +740,7 @@
|
|
|
673
740
|
},
|
|
674
741
|
discard() {
|
|
675
742
|
slash.close();
|
|
676
|
-
for (const id of
|
|
743
|
+
for (const id of draftFileIds(snapshot())) del(id);
|
|
677
744
|
uploading.clear();
|
|
678
745
|
editable.textContent = "";
|
|
679
746
|
changed();
|
|
@@ -703,6 +770,10 @@
|
|
|
703
770
|
out.push({ t: "file", id: child.getAttribute(CHIP_ATTR) ?? "", name });
|
|
704
771
|
continue;
|
|
705
772
|
}
|
|
773
|
+
if (child.hasAttribute(PICK_ATTR)) {
|
|
774
|
+
out.push({ t: "pick", files: parsePick(child.getAttribute(PICK_ATTR)) });
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
706
777
|
if (child.hasAttribute(SKILL_ATTR)) {
|
|
707
778
|
out.push({ t: "skill", name: child.getAttribute(SKILL_ATTR) ?? "" });
|
|
708
779
|
continue;
|
|
@@ -731,10 +802,144 @@
|
|
|
731
802
|
return null;
|
|
732
803
|
}
|
|
733
804
|
}
|
|
805
|
+
function parsePick(raw) {
|
|
806
|
+
try {
|
|
807
|
+
return JSON.parse(raw ?? "[]");
|
|
808
|
+
} catch {
|
|
809
|
+
return [];
|
|
810
|
+
}
|
|
811
|
+
}
|
|
734
812
|
|
|
735
|
-
// src/client/
|
|
736
|
-
function
|
|
737
|
-
|
|
813
|
+
// src/client/overlay-link.ts
|
|
814
|
+
function linkFromScript(script, api) {
|
|
815
|
+
if (script?.dataset.ezLink !== "relay") return directLink(api);
|
|
816
|
+
const shellOrigin = script.dataset.ezShell;
|
|
817
|
+
return shellOrigin ? relayLink({ shellOrigin }) : inertLink();
|
|
818
|
+
}
|
|
819
|
+
function libraryChooser(post2, fromShell) {
|
|
820
|
+
const pending = /* @__PURE__ */ new Map();
|
|
821
|
+
let seq = 0;
|
|
822
|
+
window.addEventListener("message", (e) => {
|
|
823
|
+
if (!fromShell(e)) return;
|
|
824
|
+
const data = e.data;
|
|
825
|
+
if (data?.type !== "ez:library-picked" || typeof data.reqId !== "string") return;
|
|
826
|
+
const waiting = pending.get(data.reqId);
|
|
827
|
+
pending.delete(data.reqId);
|
|
828
|
+
if (!waiting) return;
|
|
829
|
+
if (typeof data.error === "string") waiting.reject(new Error(data.error));
|
|
830
|
+
else waiting.resolve(Array.isArray(data.files) ? data.files : []);
|
|
831
|
+
});
|
|
832
|
+
return () => new Promise((resolve, reject) => {
|
|
833
|
+
const reqId = `l${++seq}-${Date.now().toString(36)}`;
|
|
834
|
+
pending.set(reqId, { resolve, reject });
|
|
835
|
+
post2({ type: "ez:library-pick", reqId });
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
function directLink(api) {
|
|
839
|
+
const post2 = (message) => window.parent?.postMessage(message, location.origin);
|
|
840
|
+
const fromShell = (e) => e.source === window.parent && e.origin === location.origin;
|
|
841
|
+
return {
|
|
842
|
+
kind: "direct",
|
|
843
|
+
post: post2,
|
|
844
|
+
annotate: async (body) => {
|
|
845
|
+
const res = await fetch(`${api}/annotations`, {
|
|
846
|
+
method: "POST",
|
|
847
|
+
headers: { "content-type": "application/json" },
|
|
848
|
+
body: JSON.stringify(body)
|
|
849
|
+
});
|
|
850
|
+
if (!res.ok) throw new Error(`annotation rejected (${res.status})`);
|
|
851
|
+
},
|
|
852
|
+
attachments: directAttachments(api),
|
|
853
|
+
...window.parent !== window ? { chooseLibrary: libraryChooser(post2, fromShell) } : {},
|
|
854
|
+
subscribe: (onSnapshot) => {
|
|
855
|
+
if (window.parent === window) {
|
|
856
|
+
const events = new EventSource(`${api}/events`);
|
|
857
|
+
events.onmessage = (e) => onSnapshot(JSON.parse(e.data));
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
window.addEventListener("message", (e) => {
|
|
861
|
+
const data = e.data;
|
|
862
|
+
if (e.source === window.parent && e.origin === location.origin && data?.type === "ez:snapshot" && data.snapshot) {
|
|
863
|
+
onSnapshot(data.snapshot);
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
},
|
|
867
|
+
fromShell: (e) => e.origin === location.origin
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
var RELAY_TIMEOUT_MS = 1e4;
|
|
871
|
+
function relayLink(config) {
|
|
872
|
+
const { shellOrigin } = config;
|
|
873
|
+
const pending = /* @__PURE__ */ new Map();
|
|
874
|
+
const listeners = [];
|
|
875
|
+
let last = null;
|
|
876
|
+
let seq = 0;
|
|
877
|
+
const fromShell = (e) => e.source === window.parent && e.origin === shellOrigin;
|
|
878
|
+
const post2 = (message) => window.parent?.postMessage(message, shellOrigin);
|
|
879
|
+
window.addEventListener("message", (e) => {
|
|
880
|
+
if (!fromShell(e)) return;
|
|
881
|
+
const data = e.data;
|
|
882
|
+
if (data?.type === "ez:relay-done" && typeof data.reqId === "string") {
|
|
883
|
+
const waiting = pending.get(data.reqId);
|
|
884
|
+
pending.delete(data.reqId);
|
|
885
|
+
if (!waiting) return;
|
|
886
|
+
if (data.ok) waiting.resolve(data.body);
|
|
887
|
+
else waiting.reject(new Error(data.body?.error ?? "refused"));
|
|
888
|
+
}
|
|
889
|
+
if (data?.type === "ez:snapshot" && data.snapshot) {
|
|
890
|
+
last = data.snapshot;
|
|
891
|
+
for (const listener of listeners) listener(data.snapshot);
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
const request = (op, transfer) => new Promise((resolve, reject) => {
|
|
895
|
+
const reqId = `r${++seq}-${Date.now().toString(36)}`;
|
|
896
|
+
pending.set(reqId, { resolve, reject });
|
|
897
|
+
window.setTimeout(() => {
|
|
898
|
+
if (pending.delete(reqId)) reject(new Error("the review did not answer"));
|
|
899
|
+
}, RELAY_TIMEOUT_MS);
|
|
900
|
+
window.parent?.postMessage({ type: "ez:relay", reqId, op }, shellOrigin, transfer);
|
|
901
|
+
});
|
|
902
|
+
return {
|
|
903
|
+
kind: "relay",
|
|
904
|
+
post: post2,
|
|
905
|
+
annotate: async (body) => {
|
|
906
|
+
await request({ op: "annotate", body });
|
|
907
|
+
},
|
|
908
|
+
attachments: {
|
|
909
|
+
upload: async (file) => {
|
|
910
|
+
const bytes = await file.arrayBuffer();
|
|
911
|
+
const name = file.name || "image.png";
|
|
912
|
+
return await request(
|
|
913
|
+
{ op: "upload", name, mime: file.type || "application/octet-stream", bytes },
|
|
914
|
+
[bytes]
|
|
915
|
+
);
|
|
916
|
+
},
|
|
917
|
+
discard: (id) => {
|
|
918
|
+
request({ op: "discard-upload", id }).catch(() => {
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
chooseLibrary: libraryChooser(post2, fromShell),
|
|
923
|
+
subscribe: (onSnapshot) => {
|
|
924
|
+
listeners.push(onSnapshot);
|
|
925
|
+
if (last) onSnapshot(last);
|
|
926
|
+
},
|
|
927
|
+
fromShell
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
function inertLink() {
|
|
931
|
+
const refused = () => Promise.reject(new Error("this frame has no review to report to"));
|
|
932
|
+
return {
|
|
933
|
+
kind: "relay",
|
|
934
|
+
post: () => {
|
|
935
|
+
},
|
|
936
|
+
annotate: refused,
|
|
937
|
+
attachments: { upload: refused, discard: () => {
|
|
938
|
+
} },
|
|
939
|
+
subscribe: () => {
|
|
940
|
+
},
|
|
941
|
+
fromShell: () => false
|
|
942
|
+
};
|
|
738
943
|
}
|
|
739
944
|
|
|
740
945
|
// src/client/variant.ts
|
|
@@ -1154,6 +1359,7 @@
|
|
|
1154
1359
|
}
|
|
1155
1360
|
})();
|
|
1156
1361
|
var API = `${PREFIX}/api`;
|
|
1362
|
+
var link = linkFromScript(document.currentScript, API);
|
|
1157
1363
|
var SOURCE_ATTR2 = "data-ez-source";
|
|
1158
1364
|
var mode = "off";
|
|
1159
1365
|
var ended = false;
|
|
@@ -1200,10 +1406,6 @@
|
|
|
1200
1406
|
badge: el("div", "ez-badge"),
|
|
1201
1407
|
pin: el("div", "ez-pin"),
|
|
1202
1408
|
markers: el("div", "ez-markers"),
|
|
1203
|
-
/** Shown only while picking: a wash at the edges of the viewport, and a pill
|
|
1204
|
-
* saying what the modifier does. The page stays clickable underneath, so the
|
|
1205
|
-
* chrome is the only thing telling the user this moment is different. */
|
|
1206
|
-
banner: el("div", "ez-pick-banner"),
|
|
1207
1409
|
/** The box being dragged, with its size read out in the corner. */
|
|
1208
1410
|
region: el("div", "ez-region"),
|
|
1209
1411
|
regionSize: el("div", "ez-region-size"),
|
|
@@ -1309,7 +1511,9 @@
|
|
|
1309
1511
|
height: Math.round(rect.height)
|
|
1310
1512
|
},
|
|
1311
1513
|
viewport: { width: window.innerWidth, height: window.innerHeight, preset: viewportPreset },
|
|
1312
|
-
page:
|
|
1514
|
+
// A canvas frame is one document with no page in the app: its `frame`,
|
|
1515
|
+
// stamped by the shell, says where it is.
|
|
1516
|
+
...link.kind === "relay" ? {} : { page: location.pathname }
|
|
1313
1517
|
};
|
|
1314
1518
|
}
|
|
1315
1519
|
var clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
@@ -1481,7 +1685,7 @@
|
|
|
1481
1685
|
const popup = el("div", "ez-popup");
|
|
1482
1686
|
const actions = el("div", "ez-actions");
|
|
1483
1687
|
const save = el("button", "ez-btn ez-btn-primary");
|
|
1484
|
-
const saveIcon = icon(
|
|
1688
|
+
const saveIcon = icon(Add01Icon, 14);
|
|
1485
1689
|
const saveLabel = document.createTextNode("\u52A0\u5165\u5F85\u9001\u6E05\u55AE");
|
|
1486
1690
|
save.append(saveIcon, saveLabel);
|
|
1487
1691
|
const cancel = el("button", "ez-btn");
|
|
@@ -1491,11 +1695,12 @@
|
|
|
1491
1695
|
const exploreTarget = subject.kind === "element" ? exploreElement : null;
|
|
1492
1696
|
let exploring = false;
|
|
1493
1697
|
const exploreHead = el("div", "ez-explore-head");
|
|
1494
|
-
exploreHead.append(icon(
|
|
1698
|
+
exploreHead.append(icon(MagicWand01Icon, 15), el("span", "ez-explore-title"));
|
|
1495
1699
|
exploreHead.querySelector(".ez-explore-title").textContent = "\u63A2\u7D22\u6A23\u5F0F";
|
|
1496
1700
|
exploreHead.hidden = true;
|
|
1497
1701
|
const attach = attachify({
|
|
1498
|
-
|
|
1702
|
+
attachments: link.attachments,
|
|
1703
|
+
...link.chooseLibrary ? { chooseLibrary: link.chooseLibrary } : {},
|
|
1499
1704
|
mk: el,
|
|
1500
1705
|
className: "ez-input",
|
|
1501
1706
|
placeholder: COMPOSE_PLACEHOLDER,
|
|
@@ -1512,7 +1717,7 @@
|
|
|
1512
1717
|
label: "Element",
|
|
1513
1718
|
hint: `\u9078\u53D6\u9801\u9762\u5143\u7D20\u6216\u7BC4\u570D`,
|
|
1514
1719
|
keywords: ["element", "pick", "ref", "reference", "\u5143\u7D20", "\u6307\u5B9A", "\u53C3\u8003", "\u6846\u9078"],
|
|
1515
|
-
icon:
|
|
1720
|
+
icon: AlignSelectionIcon,
|
|
1516
1721
|
run: () => void armPick("popup", newPickId())
|
|
1517
1722
|
},
|
|
1518
1723
|
{
|
|
@@ -1520,7 +1725,7 @@
|
|
|
1520
1725
|
label: "Explore",
|
|
1521
1726
|
hint: "\u63A2\u7D22\u6A23\u5F0F",
|
|
1522
1727
|
keywords: ["explore", "variant", "ui", "\u63A2\u7D22", "\u6A23\u5F0F", "\u7248\u672C"],
|
|
1523
|
-
icon:
|
|
1728
|
+
icon: MagicWand01Icon,
|
|
1524
1729
|
enabled: () => canExplore && !!exploreTarget && !exploring,
|
|
1525
1730
|
run: () => setExploring(true)
|
|
1526
1731
|
}
|
|
@@ -1630,12 +1835,7 @@
|
|
|
1630
1835
|
async function saveAnnotation(kind, element, comment, attachments, references, extra) {
|
|
1631
1836
|
const anchor = extra?.anchor ?? (element ? buildAnchor(element, extra?.selectedText, extra?.pin) : null);
|
|
1632
1837
|
if (!anchor) throw new Error("no anchor to save against");
|
|
1633
|
-
|
|
1634
|
-
method: "POST",
|
|
1635
|
-
headers: { "content-type": "application/json" },
|
|
1636
|
-
body: JSON.stringify({ kind, comment, attachments, references, anchor })
|
|
1637
|
-
});
|
|
1638
|
-
if (!res.ok) throw new Error(`annotation rejected (${res.status})`);
|
|
1838
|
+
await link.annotate({ kind, comment, attachments, references, anchor });
|
|
1639
1839
|
}
|
|
1640
1840
|
function corroborates(hit, anchor) {
|
|
1641
1841
|
if (!anchor.source) return true;
|
|
@@ -1785,12 +1985,14 @@
|
|
|
1785
1985
|
function renderMarkers() {
|
|
1786
1986
|
ui.markers.textContent = "";
|
|
1787
1987
|
if (pick2) return;
|
|
1788
|
-
const relevant = annotations.filter(
|
|
1789
|
-
|
|
1988
|
+
const relevant = annotations.filter(
|
|
1989
|
+
(a) => (link.kind === "relay" || a.anchor.page === location.pathname) && madeHere(a)
|
|
1990
|
+
);
|
|
1991
|
+
relevant.forEach((a) => {
|
|
1790
1992
|
const at = markerPosition(a);
|
|
1791
1993
|
if (!at) return;
|
|
1792
1994
|
const marker = el("div", "ez-marker");
|
|
1793
|
-
marker.textContent = String(
|
|
1995
|
+
marker.textContent = String(a.n ?? annotations.indexOf(a) + 1);
|
|
1794
1996
|
marker.title = a.comment;
|
|
1795
1997
|
const r = MARKER_SIZE / 2;
|
|
1796
1998
|
let top = at.top - r;
|
|
@@ -1815,12 +2017,11 @@
|
|
|
1815
2017
|
paintPopup();
|
|
1816
2018
|
});
|
|
1817
2019
|
}
|
|
1818
|
-
var MOD_LABEL = modLabel(navigator.userAgent);
|
|
1819
2020
|
var PICKING_LABEL = "\u9078\u53D6\u4E2D\u2026";
|
|
1820
2021
|
var pickSeq = 0;
|
|
1821
2022
|
var newPickId = () => `p${++pickSeq}-${Date.now().toString(36)}`;
|
|
1822
2023
|
function post(message) {
|
|
1823
|
-
|
|
2024
|
+
link.post(message);
|
|
1824
2025
|
}
|
|
1825
2026
|
function suspendPopup() {
|
|
1826
2027
|
if (!ui.popup) return false;
|
|
@@ -1843,19 +2044,6 @@
|
|
|
1843
2044
|
ui.popupAttach?.editable.focus();
|
|
1844
2045
|
}
|
|
1845
2046
|
var inExplore = false;
|
|
1846
|
-
function paintPickChrome() {
|
|
1847
|
-
const on = Boolean(pick2);
|
|
1848
|
-
ui.banner.style.display = on ? "flex" : "none";
|
|
1849
|
-
if (!pick2) return;
|
|
1850
|
-
const back = pick2.returnTo && pick2.returnTo !== location.pathname ? pick2.returnTo : null;
|
|
1851
|
-
ui.banner.textContent = "";
|
|
1852
|
-
const text = el("span", "ez-pick-text");
|
|
1853
|
-
text.textContent = back ? `${MOD_LABEL} + \u9EDE\u64CA\u5143\u7D20\u6216\u76F4\u63A5\u62D6\u66F3\u6846\u9078\u30FB\u5B8C\u6210\u5F8C\u56DE\u5230 ${back}` : `${MOD_LABEL} + \u9EDE\u64CA\u5143\u7D20\uFF0C\u6216\u62D6\u66F3\u6846\u9078\u7BC4\u570D`;
|
|
1854
|
-
const cancel = el("button", "ez-pick-cancel");
|
|
1855
|
-
cancel.textContent = "\u53D6\u6D88";
|
|
1856
|
-
cancel.onclick = () => cancelPick("escape");
|
|
1857
|
-
ui.banner.append(icon(AlignSelectionIcon_default, 14), text, cancel);
|
|
1858
|
-
}
|
|
1859
2047
|
function currentDraft() {
|
|
1860
2048
|
if (!pick2 || pick2.host !== "popup" || !ui.popupAttach || !popupSubject) return null;
|
|
1861
2049
|
return {
|
|
@@ -1881,7 +2069,7 @@
|
|
|
1881
2069
|
const draft = currentDraft();
|
|
1882
2070
|
if (draft) post({ type: "ez:draft", pickId: draft.id, draft });
|
|
1883
2071
|
}
|
|
1884
|
-
function armPick(host, id
|
|
2072
|
+
function armPick(host, id) {
|
|
1885
2073
|
if (ended || pick2) return false;
|
|
1886
2074
|
const attach = host === "popup" ? ui.popupAttach : null;
|
|
1887
2075
|
pick2 = {
|
|
@@ -1889,7 +2077,6 @@
|
|
|
1889
2077
|
host,
|
|
1890
2078
|
suspended: false,
|
|
1891
2079
|
prevHighlight: highlightTarget,
|
|
1892
|
-
returnTo,
|
|
1893
2080
|
draftAt: Date.now(),
|
|
1894
2081
|
scroll: { x: window.scrollX, y: window.scrollY }
|
|
1895
2082
|
};
|
|
@@ -1902,7 +2089,6 @@
|
|
|
1902
2089
|
document.documentElement.setAttribute("data-ez-pick", "");
|
|
1903
2090
|
hoverTarget = null;
|
|
1904
2091
|
moveHighlight(null);
|
|
1905
|
-
paintPickChrome();
|
|
1906
2092
|
scheduleRepaint();
|
|
1907
2093
|
return true;
|
|
1908
2094
|
}
|
|
@@ -1933,7 +2119,6 @@
|
|
|
1933
2119
|
document.documentElement.removeAttribute("data-ez-pick-hot");
|
|
1934
2120
|
hoverTarget = null;
|
|
1935
2121
|
moveHighlight(done.prevHighlight);
|
|
1936
|
-
paintPickChrome();
|
|
1937
2122
|
scheduleRepaint();
|
|
1938
2123
|
return done;
|
|
1939
2124
|
}
|
|
@@ -2102,7 +2287,7 @@
|
|
|
2102
2287
|
dismiss();
|
|
2103
2288
|
ui.selectionBubble?.remove();
|
|
2104
2289
|
ui.selectionBubble = null;
|
|
2105
|
-
|
|
2290
|
+
post({ type: "ez:mode", mode });
|
|
2106
2291
|
}
|
|
2107
2292
|
function onMouseMove(e) {
|
|
2108
2293
|
lastPointer = { x: e.clientX, y: e.clientY };
|
|
@@ -2231,7 +2416,7 @@
|
|
|
2231
2416
|
const text = range.toString().trim();
|
|
2232
2417
|
const rect = range.getBoundingClientRect();
|
|
2233
2418
|
const bubble = el("button", "ez-select-btn");
|
|
2234
|
-
bubble.append(icon(
|
|
2419
|
+
bubble.append(icon(TextSelectIcon, 14), document.createTextNode("\u6A19\u8A3B\u9078\u53D6\u6587\u5B57"));
|
|
2235
2420
|
Object.assign(bubble.style, {
|
|
2236
2421
|
top: `${Math.max(4, rect.bottom + window.scrollY + 6)}px`,
|
|
2237
2422
|
left: `${Math.max(4, rect.left + window.scrollX)}px`
|
|
@@ -2259,7 +2444,12 @@
|
|
|
2259
2444
|
if (w && (w.metaKey || w.ctrlKey) && window.parent !== window) {
|
|
2260
2445
|
e.preventDefault();
|
|
2261
2446
|
const unit = w.deltaMode === 1 ? 16 : w.deltaMode === 2 ? window.innerHeight : 1;
|
|
2262
|
-
post({
|
|
2447
|
+
post({
|
|
2448
|
+
type: "ez:wheel",
|
|
2449
|
+
dx: w.deltaX * unit,
|
|
2450
|
+
dy: w.deltaY * unit,
|
|
2451
|
+
...link.kind === "relay" ? { zoom: true, at: { x: w.clientX, y: w.clientY } } : {}
|
|
2452
|
+
});
|
|
2263
2453
|
return;
|
|
2264
2454
|
}
|
|
2265
2455
|
if (pick2 || !popupLive() && !held || isOwnUi(e.target)) return;
|
|
@@ -2340,6 +2530,11 @@
|
|
|
2340
2530
|
return url.pathname + url.search + url.hash;
|
|
2341
2531
|
}
|
|
2342
2532
|
function onNavClick(e) {
|
|
2533
|
+
if (link.kind === "relay") {
|
|
2534
|
+
const href = e.target?.closest?.("a[href]")?.getAttribute("href");
|
|
2535
|
+
if (href && !href.startsWith("#")) e.preventDefault();
|
|
2536
|
+
return;
|
|
2537
|
+
}
|
|
2343
2538
|
const to = linkTarget(e);
|
|
2344
2539
|
if (!to) return;
|
|
2345
2540
|
e.preventDefault();
|
|
@@ -2354,12 +2549,10 @@
|
|
|
2354
2549
|
ui.badge,
|
|
2355
2550
|
ui.pin,
|
|
2356
2551
|
ui.markers,
|
|
2357
|
-
ui.region
|
|
2358
|
-
ui.banner
|
|
2552
|
+
ui.region
|
|
2359
2553
|
);
|
|
2360
2554
|
moveHighlight(null);
|
|
2361
2555
|
movePin(null);
|
|
2362
|
-
paintPickChrome();
|
|
2363
2556
|
document.addEventListener("mousedown", onMouseDown, true);
|
|
2364
2557
|
document.addEventListener("mousemove", onMouseMove, true);
|
|
2365
2558
|
document.addEventListener("mouseleave", onMouseLeave);
|
|
@@ -2386,7 +2579,7 @@
|
|
|
2386
2579
|
subtree: true
|
|
2387
2580
|
});
|
|
2388
2581
|
window.addEventListener("message", (e) => {
|
|
2389
|
-
if (e
|
|
2582
|
+
if (!link.fromShell(e)) return;
|
|
2390
2583
|
const data = e.data;
|
|
2391
2584
|
if (data?.type === "ez:variant" && data.exploreId && data.anchor !== void 0) {
|
|
2392
2585
|
swapper.set({
|
|
@@ -2410,7 +2603,7 @@
|
|
|
2410
2603
|
setFrameZoom(typeof data.zoom === "number" ? data.zoom : 1);
|
|
2411
2604
|
}
|
|
2412
2605
|
if (data?.type === "ez:pick" && data.pickId) {
|
|
2413
|
-
armPick(data.host ?? "note", data.pickId
|
|
2606
|
+
armPick(data.host ?? "note", data.pickId);
|
|
2414
2607
|
}
|
|
2415
2608
|
if (data?.type === "ez:hold") {
|
|
2416
2609
|
held = Boolean(data.held);
|
|
@@ -2424,11 +2617,13 @@
|
|
|
2424
2617
|
}
|
|
2425
2618
|
if (data?.type === "ez:scroll-to" && typeof data.ratio === "number") scrollToRatio(data.ratio);
|
|
2426
2619
|
if (data?.type === "ez:pick-abort") cancelPick("abort");
|
|
2620
|
+
if (data?.type === "ez:pick-resolve" && data.pickId) {
|
|
2621
|
+
if (pick2?.id === data.pickId && pick2.host === "popup" && pick2.suspended && data.ref) deliverPick(data.ref);
|
|
2622
|
+
else if (data.draft) restoreDraft(data.draft);
|
|
2623
|
+
}
|
|
2427
2624
|
if (data?.type === "ez:restore" && data.draft) restoreDraft(data.draft);
|
|
2428
2625
|
});
|
|
2429
|
-
|
|
2430
|
-
events.onmessage = (e) => {
|
|
2431
|
-
const snapshot = JSON.parse(e.data);
|
|
2626
|
+
link.subscribe((snapshot) => {
|
|
2432
2627
|
annotations = snapshot.annotations;
|
|
2433
2628
|
ended = snapshot.state === "ended";
|
|
2434
2629
|
if (ended) {
|
|
@@ -2436,7 +2631,7 @@
|
|
|
2436
2631
|
setMode("off");
|
|
2437
2632
|
}
|
|
2438
2633
|
scheduleRepaint();
|
|
2439
|
-
};
|
|
2634
|
+
});
|
|
2440
2635
|
post({ type: "ez:ready", page: location.pathname, url: here() });
|
|
2441
2636
|
}
|
|
2442
2637
|
if (document.readyState === "loading") {
|