@open-wxa/wxa-runner-core 0.4.1 → 0.6.0
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/dist/index.d.mts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +55 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -10
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/frame.js +99 -2
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/host.js +155 -36
- package/dist/runtime/host.js.map +1 -1
- package/dist/runtime/worker.js +42 -0
- package/dist/runtime/worker.js.map +1 -0
- package/package.json +3 -3
package/dist/runtime/host.js
CHANGED
|
@@ -433,8 +433,11 @@
|
|
|
433
433
|
var SOURCES = ["camera", "album"];
|
|
434
434
|
var SOURCE_LABELS = { camera: "\u62CD\u6444", album: "\u4ECE\u624B\u673A\u76F8\u518C\u9009\u62E9" };
|
|
435
435
|
var DEFAULT_COUNT = 9;
|
|
436
|
+
var MEDIA_KINDS = ["image", "video"];
|
|
437
|
+
var FIRST_FRAME_TIMEOUT = 1e3;
|
|
438
|
+
var countOf = (args) => Math.max(1, Number(args.count) || DEFAULT_COUNT);
|
|
436
439
|
function createMediaApis({ showActionSheet, chooseFiles: chooseFiles2, hasUserActivation: hasUserActivation2, showImagePreview }) {
|
|
437
|
-
async function
|
|
440
|
+
async function pickFiles(args, accept) {
|
|
438
441
|
const allowed = SOURCES.filter((source2) => args.sourceType?.includes(source2));
|
|
439
442
|
const sources = allowed.length ? allowed : SOURCES;
|
|
440
443
|
let source = sources[0];
|
|
@@ -443,28 +446,33 @@
|
|
|
443
446
|
if (index === null) return null;
|
|
444
447
|
source = sources[index];
|
|
445
448
|
}
|
|
446
|
-
|
|
447
|
-
const files = await chooseFiles2({ accept: "image/*", multiple: count > 1, capture: source === "camera" });
|
|
448
|
-
return files && files.slice(0, count);
|
|
449
|
+
return chooseFiles2({ accept, multiple: countOf(args) > 1, capture: source === "camera" });
|
|
449
450
|
}
|
|
450
|
-
const
|
|
451
|
+
const saveImage = (file) => saveTempFile(file, tempFileType(file.name, file.type, "jpg"));
|
|
451
452
|
return {
|
|
452
453
|
chooseImage: async (args, { api }) => {
|
|
453
|
-
const files = await
|
|
454
|
+
const files = (await pickFiles(args, "image/*"))?.slice(0, countOf(args));
|
|
454
455
|
if (!files) return fail(api, "cancel");
|
|
455
|
-
const paths = await
|
|
456
|
+
const paths = await Promise.all(files.map(saveImage));
|
|
456
457
|
return ok(api, { tempFilePaths: paths, tempFiles: files.map((file, i) => ({ path: paths[i], size: file.size })) });
|
|
457
458
|
},
|
|
458
459
|
chooseMedia: async (args, { api }) => {
|
|
459
|
-
const mediaType = args.mediaType?.length ? args.mediaType :
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
return
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
460
|
+
const mediaType = args.mediaType?.length ? args.mediaType : MEDIA_KINDS;
|
|
461
|
+
const mix = mediaType.includes("mix");
|
|
462
|
+
const requested = MEDIA_KINDS.filter((kind) => mix || mediaType.includes(kind));
|
|
463
|
+
const kinds = requested.length ? requested : MEDIA_KINDS;
|
|
464
|
+
const picked = await pickFiles(args, kinds.map((kind) => `${kind}/*`).join(","));
|
|
465
|
+
if (!picked) return fail(api, "cancel");
|
|
466
|
+
const kindOf = (file) => kinds.length === 1 ? kinds[0] : file.type.startsWith("video/") ? "video" : "image";
|
|
467
|
+
const videos = picked.filter((file) => kindOf(file) === "video");
|
|
468
|
+
const files = (mix || !videos.length ? picked : videos).slice(0, countOf(args));
|
|
469
|
+
const tempFiles = await Promise.all(files.map(async (file) => kindOf(file) === "video" ? { ...await saveVideo(file), fileType: "video" } : { tempFilePath: await saveImage(file), size: file.size, fileType: "image" }));
|
|
470
|
+
return ok(api, { type: mix ? "mix" : tempFiles[0].fileType, tempFiles });
|
|
471
|
+
},
|
|
472
|
+
chooseVideo: async (args, { api }) => {
|
|
473
|
+
const file = (await pickFiles({ sourceType: args.sourceType, count: 1 }, "video/*"))?.[0];
|
|
474
|
+
if (!file) return fail(api, "cancel");
|
|
475
|
+
return ok(api, await saveVideo(file));
|
|
468
476
|
},
|
|
469
477
|
// 基础库已经把 current 换成了 urls 里的地址;也兼容直接传下标
|
|
470
478
|
previewImage: (args) => {
|
|
@@ -493,6 +501,45 @@
|
|
|
493
501
|
}
|
|
494
502
|
};
|
|
495
503
|
}
|
|
504
|
+
async function saveVideo(file) {
|
|
505
|
+
const [tempFilePath, { duration, width, height, thumb }] = await Promise.all([
|
|
506
|
+
saveTempFile(file, tempFileType(file.name, file.type, "mp4")),
|
|
507
|
+
readVideo(file)
|
|
508
|
+
]);
|
|
509
|
+
const thumbTempFilePath = thumb ? await saveTempFile(thumb, "jpg") : "";
|
|
510
|
+
return { tempFilePath, size: file.size, duration, height, width, thumbTempFilePath };
|
|
511
|
+
}
|
|
512
|
+
async function readVideo(file) {
|
|
513
|
+
const video = document.createElement("video");
|
|
514
|
+
video.muted = true;
|
|
515
|
+
video.preload = "auto";
|
|
516
|
+
video.src = URL.createObjectURL(file);
|
|
517
|
+
try {
|
|
518
|
+
await new Promise((resolve, reject) => {
|
|
519
|
+
video.addEventListener("loadedmetadata", resolve, { once: true });
|
|
520
|
+
video.addEventListener("error", reject, { once: true });
|
|
521
|
+
});
|
|
522
|
+
const { videoWidth: width, videoHeight: height } = video;
|
|
523
|
+
const duration = Number.isFinite(video.duration) ? video.duration : 0;
|
|
524
|
+
return { duration, width, height, thumb: width && height ? await firstFrame(video) : null };
|
|
525
|
+
} catch {
|
|
526
|
+
return { duration: 0, width: 0, height: 0, thumb: null };
|
|
527
|
+
} finally {
|
|
528
|
+
URL.revokeObjectURL(video.src);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async function firstFrame(video) {
|
|
532
|
+
const loaded = video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA || await Promise.race([
|
|
533
|
+
new Promise((resolve) => video.addEventListener("loadeddata", () => resolve(true), { once: true })),
|
|
534
|
+
new Promise((resolve) => setTimeout(() => resolve(false), FIRST_FRAME_TIMEOUT))
|
|
535
|
+
]);
|
|
536
|
+
if (!loaded) return null;
|
|
537
|
+
const canvas = document.createElement("canvas");
|
|
538
|
+
canvas.width = video.videoWidth;
|
|
539
|
+
canvas.height = video.videoHeight;
|
|
540
|
+
canvas.getContext("2d").drawImage(video, 0, 0);
|
|
541
|
+
return new Promise((resolve) => canvas.toBlob(resolve, "image/jpeg"));
|
|
542
|
+
}
|
|
496
543
|
async function fetchFile(path) {
|
|
497
544
|
const url = /^[a-z][a-z\d+.-]*:/i.test(path) ? path : "/" + path.replace(/^\//, "");
|
|
498
545
|
const res = await fetch(url);
|
|
@@ -798,11 +845,10 @@
|
|
|
798
845
|
});
|
|
799
846
|
return regionTree;
|
|
800
847
|
};
|
|
801
|
-
const showCascade = (model
|
|
848
|
+
const showCascade = (model) => {
|
|
802
849
|
const session = showPicker({
|
|
803
850
|
columns: model.columns(),
|
|
804
851
|
current: model.current(),
|
|
805
|
-
headerText,
|
|
806
852
|
onColumnChange(column, index) {
|
|
807
853
|
model.select(column, index);
|
|
808
854
|
const columns = model.columns();
|
|
@@ -816,8 +862,7 @@
|
|
|
816
862
|
showPickerView: async (args, { api }) => {
|
|
817
863
|
const result = await showPicker({
|
|
818
864
|
columns: [labels(args.array)],
|
|
819
|
-
current: [Number(args.current) || 0]
|
|
820
|
-
headerText: args.headerText
|
|
865
|
+
current: [Number(args.current) || 0]
|
|
821
866
|
}).result;
|
|
822
867
|
return result ? ok(api, { index: result[0] }) : fail(api, "cancel");
|
|
823
868
|
},
|
|
@@ -825,7 +870,6 @@
|
|
|
825
870
|
const session = showPicker({
|
|
826
871
|
columns: (args.array || []).map(labels),
|
|
827
872
|
current: (args.current || []).map((index) => Number(index) || 0),
|
|
828
|
-
headerText: args.headerText,
|
|
829
873
|
onColumnChange: (column, current) => emitToWebview(webviewId, "onMultiPickerViewChange", { column, current })
|
|
830
874
|
});
|
|
831
875
|
multiPicker = session;
|
|
@@ -840,7 +884,7 @@
|
|
|
840
884
|
},
|
|
841
885
|
showDatePickerView: async (args, { api }) => {
|
|
842
886
|
const model = new DateCascade(args.mode === "time" ? "time" : "date", args.fields, args.range || {}, String(args.current || ""));
|
|
843
|
-
const result = await showCascade(model
|
|
887
|
+
const result = await showCascade(model);
|
|
844
888
|
return result ? ok(api, { value: model.value() }) : fail(api, "cancel");
|
|
845
889
|
},
|
|
846
890
|
showAddressPickerView: async (args, { api }) => {
|
|
@@ -920,7 +964,7 @@
|
|
|
920
964
|
}
|
|
921
965
|
label(column, value) {
|
|
922
966
|
if (this.mode === "time") return pad(value);
|
|
923
|
-
return value +
|
|
967
|
+
return column === 0 ? value + "\u5E74" : pad(value) + ["\u6708", "\u65E5"][column - 1];
|
|
924
968
|
}
|
|
925
969
|
};
|
|
926
970
|
function parseParts(text) {
|
|
@@ -1257,6 +1301,7 @@
|
|
|
1257
1301
|
names.add(normalizeName(pkg.root));
|
|
1258
1302
|
if (pkg.name) names.add(normalizeName(pkg.name));
|
|
1259
1303
|
}
|
|
1304
|
+
if (typeof options.workers === "object" && options.workers.isSubpackage) names.add("workers.js");
|
|
1260
1305
|
let taskSeq2 = 0;
|
|
1261
1306
|
const createLoadSubPackageTask = (args, { api }) => {
|
|
1262
1307
|
const moduleName = args.moduleName;
|
|
@@ -1578,6 +1623,18 @@
|
|
|
1578
1623
|
if (this.bridge && this.win) fn(this.bridge, this.win);
|
|
1579
1624
|
else this.pending.push(fn);
|
|
1580
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* 把逻辑层的画布放进这一页编号为 canvasNumber 的 wx-canvas,盖在它自己的 canvas 上(样式见 webviewHtml 的 .wxa-service-canvas)。
|
|
1628
|
+
* 编号在 wx-canvas 的组件实例上,DOM 节点经 __wxElement 找到组件实例
|
|
1629
|
+
*/
|
|
1630
|
+
placeCanvas(canvas, canvasNumber) {
|
|
1631
|
+
const target = Array.from(this.win?.document.querySelectorAll("wx-canvas") ?? []).find((element2) => element2.__wxElement?._canvasNumber === canvasNumber);
|
|
1632
|
+
const own = target?.querySelector(":scope > canvas");
|
|
1633
|
+
if (!own) return false;
|
|
1634
|
+
canvas.classList.add("wxa-service-canvas");
|
|
1635
|
+
own.after(canvas);
|
|
1636
|
+
return true;
|
|
1637
|
+
}
|
|
1581
1638
|
/** 页面样式里的 env(safe-area-inset-*) 构建时已改写成这些变量,见 rewriteSafeAreaInsets */
|
|
1582
1639
|
setSafeAreaInsets(insets) {
|
|
1583
1640
|
this.dispatch((_bridge, win) => {
|
|
@@ -1694,7 +1751,7 @@
|
|
|
1694
1751
|
var DEVICE_BEZEL = 13;
|
|
1695
1752
|
var STAGE_PADDING = 24;
|
|
1696
1753
|
var STAGE_GAP = 16;
|
|
1697
|
-
var PICKER_ITEM_HEIGHT =
|
|
1754
|
+
var PICKER_ITEM_HEIGHT = 48;
|
|
1698
1755
|
var SHELL_CSS = `
|
|
1699
1756
|
html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50% 0%, #f6f7f9 0%, #e6e9ee 100%); font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; }
|
|
1700
1757
|
.wxa-stage { min-height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: ${STAGE_GAP}px; padding: ${STAGE_PADDING}px; box-sizing: border-box; }
|
|
@@ -1748,18 +1805,23 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
1748
1805
|
.wxa-actionsheet-alert { padding: 16px; font-size: 13px; color: #888; text-align: center; background: #fff; }
|
|
1749
1806
|
.wxa-actionsheet button { display: block; width: 100%; height: 56px; border: 0; border-top: 1px solid rgba(0,0,0,.06); background: #fff; font-size: 17px; cursor: pointer; }
|
|
1750
1807
|
.wxa-actionsheet .wxa-actionsheet-cancel { margin-top: 8px; border-top: 0; }
|
|
1751
|
-
.wxa-picker {
|
|
1752
|
-
.wxa-picker
|
|
1753
|
-
.wxa-picker-header
|
|
1754
|
-
.wxa-picker-
|
|
1755
|
-
.wxa-picker-
|
|
1756
|
-
.wxa-picker-
|
|
1757
|
-
.wxa-picker-
|
|
1808
|
+
.wxa-picker-layer .wxa-mask.is-dim { background: rgba(0,0,0,.6); animation: wxa-fade-in .3s ease forwards; }
|
|
1809
|
+
.wxa-picker { position: absolute; left: 0; right: 0; bottom: 0; padding-bottom: var(--wxa-safe-bottom, 0px); background: #fff; pointer-events: auto; user-select: none; animation: wxa-slide-up .3s ease forwards; }
|
|
1810
|
+
.wxa-picker-header { position: relative; display: flex; padding: 16px; font-size: 17px; line-height: 1.4; }
|
|
1811
|
+
.wxa-picker-header::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1px solid rgba(0,0,0,.1); transform: scaleY(.5); transform-origin: 0 100%; }
|
|
1812
|
+
.wxa-picker-header button { flex: 1; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
|
|
1813
|
+
.wxa-picker-cancel { color: rgba(0,0,0,.5); text-align: left; }
|
|
1814
|
+
.wxa-picker-confirm { color: #07c160; text-align: right; }
|
|
1815
|
+
.wxa-picker-body { position: relative; display: flex; height: ${PICKER_ITEM_HEIGHT * 5}px; overflow: hidden; }
|
|
1758
1816
|
.wxa-picker-column { flex: 1; min-width: 0; overflow-y: auto; padding: ${PICKER_ITEM_HEIGHT * 2}px 0; box-sizing: border-box; scroll-snap-type: y mandatory; overscroll-behavior: contain; scrollbar-width: none; }
|
|
1759
1817
|
.wxa-picker-column::-webkit-scrollbar { display: none; }
|
|
1760
|
-
|
|
1761
|
-
.wxa-picker-item
|
|
1762
|
-
.wxa-picker-
|
|
1818
|
+
/* \u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u9009\u9879\u6CA1\u6709\u5355\u72EC\u8BBE\u7F6E\u5B57\u53F7\uFF0C\u7EE7\u627F\u5230\u7684\u662F 11px\uFF08\u6309\u5B83\u7684\u622A\u56FE\u91CF\u5F97\uFF09 */
|
|
1819
|
+
.wxa-picker-item { height: ${PICKER_ITEM_HEIGHT}px; line-height: ${PICKER_ITEM_HEIGHT}px; overflow: hidden; font-size: 11px; color: rgba(0,0,0,.9); text-align: center; white-space: nowrap; text-overflow: ellipsis; scroll-snap-align: center; cursor: pointer; }
|
|
1820
|
+
.wxa-picker-mask { position: absolute; inset: 0; z-index: 1; pointer-events: none; background-image: linear-gradient(180deg, rgba(255,255,255,.95), rgba(255,255,255,.6)), linear-gradient(0deg, rgba(255,255,255,.95), rgba(255,255,255,.6)); background-position: top, bottom; background-size: 100% 92px; background-repeat: no-repeat; }
|
|
1821
|
+
.wxa-picker-indicator { position: absolute; left: 0; right: 0; top: 92px; z-index: 1; height: 56px; pointer-events: none; }
|
|
1822
|
+
.wxa-picker-indicator::before, .wxa-picker-indicator::after { content: ''; position: absolute; left: 0; right: 0; height: 1px; transform: scaleY(.5); }
|
|
1823
|
+
.wxa-picker-indicator::before { top: 0; border-top: 1px solid rgba(0,0,0,.1); transform-origin: 0 0; }
|
|
1824
|
+
.wxa-picker-indicator::after { bottom: 0; border-bottom: 1px solid rgba(0,0,0,.1); transform-origin: 0 100%; }
|
|
1763
1825
|
.wxa-preview { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: #000; pointer-events: auto; }
|
|
1764
1826
|
.wxa-preview-image { max-width: 100%; max-height: 100%; object-fit: contain; }
|
|
1765
1827
|
.wxa-preview-position { position: absolute; top: 60px; left: 0; right: 0; color: #fff; font-size: 15px; text-align: center; pointer-events: none; }
|
|
@@ -1778,6 +1840,8 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
1778
1840
|
.wxa-notice-close { flex: none; width: 20px; height: 20px; padding: 0; border: 0; border-radius: 50%; background: none; color: #999; font-size: 16px; line-height: 20px; cursor: pointer; }
|
|
1779
1841
|
.wxa-notice-close:hover { background: rgba(0,0,0,.06); color: #111214; }
|
|
1780
1842
|
@keyframes wxa-spin { to { transform: rotate(360deg); } }
|
|
1843
|
+
@keyframes wxa-fade-in { from { opacity: 0; } }
|
|
1844
|
+
@keyframes wxa-slide-up { from { transform: translateY(100%); } }
|
|
1781
1845
|
@keyframes wxa-notice-in { from { opacity: 0; transform: translateY(-8px); } }
|
|
1782
1846
|
`;
|
|
1783
1847
|
|
|
@@ -1795,10 +1859,10 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
1795
1859
|
const header = element("div", "wxa-picker-header");
|
|
1796
1860
|
const cancel = element("button", "wxa-picker-cancel", "\u53D6\u6D88");
|
|
1797
1861
|
const confirm = element("button", "wxa-picker-confirm", "\u786E\u5B9A");
|
|
1798
|
-
header.append(cancel,
|
|
1862
|
+
header.append(cancel, confirm);
|
|
1799
1863
|
const body = element("div", "wxa-picker-body");
|
|
1800
1864
|
const columns = options.columns.map((_, index) => new PickerColumn((next) => options.onColumnChange?.(index, next)));
|
|
1801
|
-
body.append(...columns.map((column) => column.el), element("div", "wxa-picker-indicator"));
|
|
1865
|
+
body.append(...columns.map((column) => column.el), element("div", "wxa-picker-mask"), element("div", "wxa-picker-indicator"));
|
|
1802
1866
|
sheet.append(header, body);
|
|
1803
1867
|
layer.append(mask, sheet);
|
|
1804
1868
|
container.appendChild(layer);
|
|
@@ -2200,6 +2264,8 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2200
2264
|
// src/runtime/host/Host.ts
|
|
2201
2265
|
var ROUTE_DONE_DELAY = 300;
|
|
2202
2266
|
var PAGE_LOAD_TIMEOUT = 15e3;
|
|
2267
|
+
var BINDING_CANVAS_TYPES = /* @__PURE__ */ new Set(["2d", "webgl", "webgl2"]);
|
|
2268
|
+
var PROBE_TOP = -54321;
|
|
2203
2269
|
var Host = class {
|
|
2204
2270
|
constructor(info, root) {
|
|
2205
2271
|
this.info = info;
|
|
@@ -2222,6 +2288,8 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2222
2288
|
this.nextWebviewId = 1;
|
|
2223
2289
|
this.routeChain = Promise.resolve();
|
|
2224
2290
|
this.routeListeners = [];
|
|
2291
|
+
/** 渲染层报来的 2d、webgl 画布,按编号记下所在页面和最近的位置,供 placeCanvas 认出逻辑层的画布元素 */
|
|
2292
|
+
this.canvases = /* @__PURE__ */ new Map();
|
|
2225
2293
|
this.device = info.device;
|
|
2226
2294
|
this.shell = new PhoneShell(root, info.device);
|
|
2227
2295
|
this.tabPaths = new Set((info.wxConfig.tabBar?.list || []).map((item) => stripHtml(item.pagePath)));
|
|
@@ -2260,6 +2328,30 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2260
2328
|
registerAppContext(win) {
|
|
2261
2329
|
this.appContext = win;
|
|
2262
2330
|
}
|
|
2331
|
+
/**
|
|
2332
|
+
* 逻辑层的画布元素上没有编号,只能问基础库:给每个还没放好的同类型画布发一条 top 带记号的 canvasUpdated,
|
|
2333
|
+
* 基础库把位置写到那个编号的元素上,记号落在这个元素上就是它;随后用原来的位置再发一次,恢复原样。
|
|
2334
|
+
* 基础库只在类型与画布一致时才调到元素的 getContext,按类型筛选不会漏掉
|
|
2335
|
+
*/
|
|
2336
|
+
placeCanvas(canvas, type) {
|
|
2337
|
+
const service = this.service;
|
|
2338
|
+
if (!service) return;
|
|
2339
|
+
const update = (canvasNumber, record, top) => service.bridge.__dispatchSub(
|
|
2340
|
+
"canvasUpdated",
|
|
2341
|
+
this.cloneForService({ data: { canvasNumber, ...record.box, top }, options: { timestamp: Date.now() } }),
|
|
2342
|
+
record.webviewId
|
|
2343
|
+
);
|
|
2344
|
+
for (const [canvasNumber, record] of this.canvases) {
|
|
2345
|
+
if (record.placed || record.type !== type) continue;
|
|
2346
|
+
update(canvasNumber, record, PROBE_TOP);
|
|
2347
|
+
const matched = canvas.style.top === `${PROBE_TOP}px`;
|
|
2348
|
+
update(canvasNumber, record, record.box.top);
|
|
2349
|
+
if (matched) {
|
|
2350
|
+
record.placed = this.pages.get(record.webviewId)?.placeCanvas(canvas, canvasNumber) ?? false;
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2263
2355
|
frameLoaded(kind, webviewId) {
|
|
2264
2356
|
if (kind === "service") this.serviceLoaded();
|
|
2265
2357
|
else this.pages.get(webviewId)?.loaded();
|
|
@@ -2283,11 +2375,27 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2283
2375
|
}
|
|
2284
2376
|
if (event === "operateMapCallback" && this.mapOperations.receive(data)) return;
|
|
2285
2377
|
const fromId = this.webviewIdOf(win);
|
|
2378
|
+
this.trackCanvas(event, data?.data, fromId);
|
|
2286
2379
|
const service = this.service;
|
|
2287
2380
|
if (!service) return;
|
|
2288
2381
|
const payload = this.cloneForService(data);
|
|
2289
2382
|
queueMicrotask(() => service.bridge.__dispatchSub(event, payload, fromId));
|
|
2290
2383
|
}
|
|
2384
|
+
/**
|
|
2385
|
+
* xr-frame 的画布不记:基础库收到它的 canvasUpdated 会派发 resize 给 xr-frame,探测会带来多余的 resize,
|
|
2386
|
+
* 而 xr-frame 在 wxa-runner 里没有验证过,保持原样
|
|
2387
|
+
*/
|
|
2388
|
+
trackCanvas(event, data, webviewId) {
|
|
2389
|
+
if (!data) return;
|
|
2390
|
+
const record = this.canvases.get(data.canvasNumber);
|
|
2391
|
+
if (event === "canvasInserted" && data.type && BINDING_CANVAS_TYPES.has(data.type) && !data.isXrFrame) {
|
|
2392
|
+
this.canvases.set(data.canvasNumber, { webviewId, type: data.type, box: { top: 0, left: 0, width: 0, height: 0, ...boxOf(data) }, placed: false });
|
|
2393
|
+
} else if (event === "canvasUpdated" && record) {
|
|
2394
|
+
record.box = { ...record.box, ...boxOf(data) };
|
|
2395
|
+
} else if (event === "canvasRemoved") {
|
|
2396
|
+
this.canvases.delete(data.canvasNumber);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2291
2399
|
/** 不指定目标时发给所有页面:旧版 canvas 的绘制指令就是这样发的,由 canvasNumber 找到对应画布 */
|
|
2292
2400
|
publishToPages(event, data, webviewIds) {
|
|
2293
2401
|
const targets = webviewIds?.length ? webviewIds.map((id) => this.pages.get(Number(id))) : this.livePages();
|
|
@@ -2445,6 +2553,9 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2445
2553
|
if (this.tabPages.get(page.path) === page) this.tabPages.delete(page.path);
|
|
2446
2554
|
this.pages.delete(page.id);
|
|
2447
2555
|
page.destroy();
|
|
2556
|
+
for (const [canvasNumber, record] of this.canvases) {
|
|
2557
|
+
if (record.webviewId === page.id) this.canvases.delete(canvasNumber);
|
|
2558
|
+
}
|
|
2448
2559
|
}
|
|
2449
2560
|
activate(page, openType) {
|
|
2450
2561
|
for (const other of this.pages.values()) {
|
|
@@ -2537,6 +2648,7 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2537
2648
|
...createStorageApis(this.storage),
|
|
2538
2649
|
...createSubpackageApis({
|
|
2539
2650
|
subPackages: this.info.wxConfig.subPackages || [],
|
|
2651
|
+
workers: this.info.wxConfig.workers,
|
|
2540
2652
|
emit: (event, data) => this.emitToService(event, data)
|
|
2541
2653
|
}),
|
|
2542
2654
|
...createSavedFileApis(this.storage),
|
|
@@ -2593,6 +2705,13 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2593
2705
|
}
|
|
2594
2706
|
};
|
|
2595
2707
|
}
|
|
2708
|
+
function boxOf(data) {
|
|
2709
|
+
const box = {};
|
|
2710
|
+
for (const key of ["top", "left", "width", "height"]) {
|
|
2711
|
+
if (data[key] !== void 0) box[key] = data[key];
|
|
2712
|
+
}
|
|
2713
|
+
return box;
|
|
2714
|
+
}
|
|
2596
2715
|
function stripHtml(path) {
|
|
2597
2716
|
return path.replace(/\.html$/, "");
|
|
2598
2717
|
}
|