@open-wxa/wxa-runner-core 0.10.1 → 0.12.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 +51 -6
- package/dist/index.d.ts +51 -6
- package/dist/index.js +489 -298
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +478 -293
- package/dist/index.mjs.map +1 -1
- package/dist/runtime/host.js +203 -31
- package/dist/runtime/host.js.map +1 -1
- package/dist/runtime/sw.js +24 -20
- package/dist/runtime/sw.js.map +1 -1
- package/dist/{setup-Bac8XdhR.d.mts → setup-D0ubZt2C.d.mts} +6 -0
- package/dist/{setup-Bac8XdhR.d.ts → setup-D0ubZt2C.d.ts} +6 -0
- package/dist/setup.d.mts +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/test-api.d.mts +12 -2
- package/dist/test-api.d.ts +12 -2
- package/dist/{testApi-BOZSXSnV.d.ts → testApi-Df0ltBI6.d.ts} +29 -2
- package/dist/{testApi-DHuEW5Cl.d.mts → testApi-x2Yph6M2.d.mts} +29 -2
- package/dist/web.d.mts +270 -0
- package/dist/web.d.ts +270 -0
- package/dist/web.js +700 -0
- package/dist/web.js.map +1 -0
- package/dist/web.mjs +677 -0
- package/dist/web.mjs.map +1 -0
- package/package.json +11 -3
package/dist/runtime/host.js
CHANGED
|
@@ -1018,9 +1018,9 @@ ${frames}` : "");
|
|
|
1018
1018
|
(this.replies.get(query.id) ?? Promise.resolve(null)).then((reply) => port.postMessage(reply));
|
|
1019
1019
|
}
|
|
1020
1020
|
};
|
|
1021
|
-
function installMockMirror() {
|
|
1022
|
-
if (navigator.webdriver || !navigator.serviceWorker) return null;
|
|
1023
|
-
navigator.serviceWorker.register(SERVICE_WORKER_URL, { scope: "/" }).catch((error) => console.warn("[wxa-runner] Service Worker \u6CE8\u518C\u5931\u8D25\uFF0C\u88AB\u62E6\u622A\u7684\u8BF7\u6C42\u4E0D\u4F1A\u663E\u793A\u5728 Network \u9762\u677F\u91CC", error));
|
|
1021
|
+
function installMockMirror(externalServiceWorker = false) {
|
|
1022
|
+
if (!externalServiceWorker && navigator.webdriver || !navigator.serviceWorker) return null;
|
|
1023
|
+
if (!externalServiceWorker) navigator.serviceWorker.register(SERVICE_WORKER_URL, { scope: "/" }).catch((error) => console.warn("[wxa-runner] Service Worker \u6CE8\u518C\u5931\u8D25\uFF0C\u88AB\u62E6\u622A\u7684\u8BF7\u6C42\u4E0D\u4F1A\u663E\u793A\u5728 Network \u9762\u677F\u91CC", error));
|
|
1024
1024
|
return new MockMirror(navigator.serviceWorker);
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
@@ -1697,16 +1697,11 @@ ${frames}` : "");
|
|
|
1697
1697
|
}
|
|
1698
1698
|
|
|
1699
1699
|
// src/runtime/host/api/webView.ts
|
|
1700
|
-
function createWebViewApis({ documentOf, emitToWebview }) {
|
|
1700
|
+
function createWebViewApis({ documentOf, emitToWebview, windows }) {
|
|
1701
|
+
if (windows) return createWindowApis(documentOf, windows);
|
|
1701
1702
|
const find = (webviewId, htmlId) => documentOf(webviewId)?.querySelector(`iframe[data-wxa-html-id="${Number(htmlId)}"]`) ?? null;
|
|
1702
1703
|
const reportStart = (webviewId, htmlId, src) => emitToWebview(webviewId, "onWebviewStartLoad", { htmlId, src, isMainFrame: true });
|
|
1703
1704
|
const reportFinish = (webviewId, htmlId, src) => emitToWebview(webviewId, "onWebviewFinishLoad", { htmlId, src });
|
|
1704
|
-
const place = (frame, position) => {
|
|
1705
|
-
if (!position) return;
|
|
1706
|
-
for (const side of ["left", "top", "width", "height"]) {
|
|
1707
|
-
if (typeof position[side] === "number") frame.style[side] = `${position[side]}px`;
|
|
1708
|
-
}
|
|
1709
|
-
};
|
|
1710
1705
|
return {
|
|
1711
1706
|
insertHTMLWebView: (args, { api, webviewId }) => {
|
|
1712
1707
|
const doc = documentOf(webviewId);
|
|
@@ -1737,7 +1732,9 @@ ${frames}` : "");
|
|
|
1737
1732
|
place(frame, args.position);
|
|
1738
1733
|
if (args.src) {
|
|
1739
1734
|
const src = String(args.src);
|
|
1735
|
+
warnCrossSite(src);
|
|
1740
1736
|
frame.dataset.wxaLoading = src;
|
|
1737
|
+
frame.dataset.wxaSrc = src;
|
|
1741
1738
|
reportStart(webviewId, Number(args.htmlId), src);
|
|
1742
1739
|
frame.src = src;
|
|
1743
1740
|
}
|
|
@@ -1749,6 +1746,161 @@ ${frames}` : "");
|
|
|
1749
1746
|
}
|
|
1750
1747
|
};
|
|
1751
1748
|
}
|
|
1749
|
+
function createWindowApis(documentOf, windows) {
|
|
1750
|
+
return {
|
|
1751
|
+
insertHTMLWebView: (args, { api, webviewId }) => {
|
|
1752
|
+
const doc = documentOf(webviewId);
|
|
1753
|
+
if (!doc) return fail(api, "page not found");
|
|
1754
|
+
windows.insert(webviewId, Number(args.htmlId), doc, args.position);
|
|
1755
|
+
return ok(api);
|
|
1756
|
+
},
|
|
1757
|
+
updateHTMLWebView: (args, { api, webviewId }) => {
|
|
1758
|
+
if (!windows.update(webviewId, Number(args.htmlId), args.position, args.src ? String(args.src) : void 0)) {
|
|
1759
|
+
return fail(api, "web-view not found");
|
|
1760
|
+
}
|
|
1761
|
+
return ok(api);
|
|
1762
|
+
},
|
|
1763
|
+
removeHTMLWebView: (args, { api, webviewId }) => {
|
|
1764
|
+
windows.remove(webviewId, Number(args.htmlId));
|
|
1765
|
+
return ok(api);
|
|
1766
|
+
}
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
function iframeWebViews(doc) {
|
|
1770
|
+
return Array.from(doc?.querySelectorAll("iframe[data-wxa-src]") ?? []).map((frame) => ({ src: frame.dataset.wxaSrc, windowName: null }));
|
|
1771
|
+
}
|
|
1772
|
+
var WebViewWindows = class {
|
|
1773
|
+
/** @param isShown 页面当前是否显示:隐藏的页面先记下地址,显示时再打开窗口 */
|
|
1774
|
+
constructor(device, isShown) {
|
|
1775
|
+
this.device = device;
|
|
1776
|
+
this.isShown = isShown;
|
|
1777
|
+
this.records = /* @__PURE__ */ new Map();
|
|
1778
|
+
}
|
|
1779
|
+
insert(webviewId, htmlId, doc, position) {
|
|
1780
|
+
const previous = this.records.get(windowName(webviewId, htmlId));
|
|
1781
|
+
previous?.placeholder.remove();
|
|
1782
|
+
const placeholder = doc.createElement("div");
|
|
1783
|
+
placeholder.dataset.wxaHtmlId = String(htmlId);
|
|
1784
|
+
placeholder.style.cssText = "position:fixed;z-index:2147483647;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:24px;background:#f7f7f7;color:#666;font:14px/1.6 sans-serif;text-align:center;word-break:break-all";
|
|
1785
|
+
const status = doc.createElement("div");
|
|
1786
|
+
const button = doc.createElement("button");
|
|
1787
|
+
button.textContent = "\u5728\u65B0\u7A97\u53E3\u6253\u5F00 H5";
|
|
1788
|
+
button.style.cssText = "padding:8px 16px;border:0;border-radius:4px;background:#07c160;color:#fff;font-size:14px";
|
|
1789
|
+
placeholder.append(status, button);
|
|
1790
|
+
place(placeholder, position);
|
|
1791
|
+
doc.body.appendChild(placeholder);
|
|
1792
|
+
const record = { webviewId, name: windowName(webviewId, htmlId), placeholder, status, src: previous?.src, win: previous?.win ?? null };
|
|
1793
|
+
this.records.set(record.name, record);
|
|
1794
|
+
button.addEventListener("click", () => {
|
|
1795
|
+
if (record.win && !record.win.closed) record.win.focus();
|
|
1796
|
+
else this.open(record);
|
|
1797
|
+
});
|
|
1798
|
+
this.render(record);
|
|
1799
|
+
}
|
|
1800
|
+
/** @returns 找不到这个 web-view 时为 false */
|
|
1801
|
+
update(webviewId, htmlId, position, src) {
|
|
1802
|
+
const record = this.records.get(windowName(webviewId, htmlId));
|
|
1803
|
+
if (!record) return false;
|
|
1804
|
+
place(record.placeholder, position);
|
|
1805
|
+
if (src && src !== record.src) {
|
|
1806
|
+
record.src = src;
|
|
1807
|
+
if (this.isShown(webviewId)) this.open(record);
|
|
1808
|
+
else this.render(record);
|
|
1809
|
+
}
|
|
1810
|
+
return true;
|
|
1811
|
+
}
|
|
1812
|
+
remove(webviewId, htmlId) {
|
|
1813
|
+
const record = this.records.get(windowName(webviewId, htmlId));
|
|
1814
|
+
if (!record) return;
|
|
1815
|
+
this.records.delete(record.name);
|
|
1816
|
+
close(record);
|
|
1817
|
+
record.placeholder.remove();
|
|
1818
|
+
}
|
|
1819
|
+
pageShown(webviewId) {
|
|
1820
|
+
for (const record of this.recordsOf(webviewId)) {
|
|
1821
|
+
if (record.src && !(record.win && !record.win.closed)) this.open(record);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
pageHidden(webviewId) {
|
|
1825
|
+
for (const record of this.recordsOf(webviewId)) {
|
|
1826
|
+
close(record);
|
|
1827
|
+
this.render(record);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
/** 页面关闭:渲染层已经或即将被删除,不必再动占位 */
|
|
1831
|
+
pageDestroyed(webviewId) {
|
|
1832
|
+
for (const record of this.recordsOf(webviewId)) {
|
|
1833
|
+
this.records.delete(record.name);
|
|
1834
|
+
close(record);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
closeAll() {
|
|
1838
|
+
for (const record of this.records.values()) close(record);
|
|
1839
|
+
}
|
|
1840
|
+
/** 页面里的 web-view,按创建顺序;还没设置 src 的不算 */
|
|
1841
|
+
list(webviewId) {
|
|
1842
|
+
return this.recordsOf(webviewId).flatMap((record) => record.src ? [{ src: record.src, windowName: record.name }] : []);
|
|
1843
|
+
}
|
|
1844
|
+
recordsOf(webviewId) {
|
|
1845
|
+
return [...this.records.values()].filter((record) => record.webviewId === webviewId);
|
|
1846
|
+
}
|
|
1847
|
+
open(record) {
|
|
1848
|
+
if (!record.src) return;
|
|
1849
|
+
if (record.win && !record.win.closed) {
|
|
1850
|
+
record.win.location.href = record.src;
|
|
1851
|
+
} else {
|
|
1852
|
+
const features = `popup,width=${this.device.screenWidth},height=${this.device.screenHeight}`;
|
|
1853
|
+
record.win = window.open(record.src, record.name, features);
|
|
1854
|
+
if (record.win) notify("open", record.name, record.src);
|
|
1855
|
+
}
|
|
1856
|
+
this.render(record);
|
|
1857
|
+
}
|
|
1858
|
+
render(record) {
|
|
1859
|
+
const opened = record.win && !record.win.closed;
|
|
1860
|
+
const [title, detail] = !record.src ? ["web-view \u8FD8\u6CA1\u6709\u8BBE\u7F6E src", ""] : opened ? ["H5 \u5DF2\u5728\u65B0\u7A97\u53E3\u6253\u5F00", record.src] : record.win === null && this.isShown(record.webviewId) ? ["\u6D4F\u89C8\u5668\u62E6\u622A\u4E86\u5F39\u51FA\u7A97\u53E3\uFF0C\u70B9\u4E0B\u9762\u7684\u6309\u94AE\u6253\u5F00 H5", record.src] : ["H5 \u5728\u65B0\u7A97\u53E3\u6253\u5F00", record.src];
|
|
1861
|
+
record.status.textContent = "";
|
|
1862
|
+
const heading = record.status.ownerDocument.createElement("div");
|
|
1863
|
+
heading.textContent = title;
|
|
1864
|
+
heading.style.cssText = "color:#333;font-size:16px";
|
|
1865
|
+
record.status.append(heading);
|
|
1866
|
+
if (detail) record.status.append(detail);
|
|
1867
|
+
}
|
|
1868
|
+
};
|
|
1869
|
+
function windowName(webviewId, htmlId) {
|
|
1870
|
+
return `wxa-h5-${webviewId}-${htmlId}`;
|
|
1871
|
+
}
|
|
1872
|
+
function close(record) {
|
|
1873
|
+
if (!record.win) return;
|
|
1874
|
+
record.win.close();
|
|
1875
|
+
record.win = null;
|
|
1876
|
+
notify("close", record.name);
|
|
1877
|
+
}
|
|
1878
|
+
function notify(type, name, src) {
|
|
1879
|
+
const listener = window.__wxa_webview_window_event__;
|
|
1880
|
+
listener?.(type, name, src)?.catch(() => void 0);
|
|
1881
|
+
}
|
|
1882
|
+
function place(element2, position) {
|
|
1883
|
+
if (!position) return;
|
|
1884
|
+
for (const side of ["left", "top", "width", "height"]) {
|
|
1885
|
+
if (typeof position[side] === "number") element2.style[side] = `${position[side]}px`;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
var warnedOrigins = /* @__PURE__ */ new Set();
|
|
1889
|
+
function warnCrossSite(src) {
|
|
1890
|
+
let url;
|
|
1891
|
+
try {
|
|
1892
|
+
url = new URL(src, location.href);
|
|
1893
|
+
} catch {
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
if (!["http:", "https:"].includes(url.protocol)) return;
|
|
1897
|
+
if (url.hostname === location.hostname && url.protocol === location.protocol) return;
|
|
1898
|
+
if (warnedOrigins.has(url.origin)) return;
|
|
1899
|
+
warnedOrigins.add(url.origin);
|
|
1900
|
+
console.warn(
|
|
1901
|
+
`[wxa-runner] web-view \u52A0\u8F7D\u7684 ${url.origin} \u4E0E\u6A21\u62DF\u5668\uFF08${location.origin}\uFF09\u4E0D\u662F\u540C\u4E00\u4E2A\u7AD9\u70B9\uFF0C\u6D4F\u89C8\u5668\u6309\u8DE8\u7AD9\u5D4C\u5165\u5904\u7406\uFF0C\u7F51\u9875\u7684 Cookie \u53EF\u80FD\u4E0D\u751F\u6548\uFF08\u5FAE\u4FE1\u91CC\u7684\u5C0F\u7A0B\u5E8F\u6CA1\u6709\u8FD9\u4E2A\u95EE\u9898\uFF09\u3002\u9700\u8981 Cookie \u65F6\u8BA9\u7F51\u9875\u5728\u65B0\u7A97\u53E3\u6253\u5F00\uFF1A\u547D\u4EE4\u884C\u52A0 --webview-window\uFF0CPlaywright \u7528 test.use({ wxaWebView: 'window' })`
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1752
1904
|
function readableUrl(frame) {
|
|
1753
1905
|
try {
|
|
1754
1906
|
return frame.contentWindow?.location.href ?? null;
|
|
@@ -2089,15 +2241,15 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2089
2241
|
layer.append(mask, sheet);
|
|
2090
2242
|
container.appendChild(layer);
|
|
2091
2243
|
columns.forEach((column, index) => column.setItems(options.columns[index], options.current[index] ?? 0));
|
|
2092
|
-
const
|
|
2244
|
+
const close2 = (value) => {
|
|
2093
2245
|
layer.remove();
|
|
2094
2246
|
resolve(value);
|
|
2095
2247
|
};
|
|
2096
|
-
cancel.addEventListener("click", () =>
|
|
2097
|
-
mask.addEventListener("click", () =>
|
|
2248
|
+
cancel.addEventListener("click", () => close2(null));
|
|
2249
|
+
mask.addEventListener("click", () => close2(null));
|
|
2098
2250
|
confirm.addEventListener("click", () => {
|
|
2099
2251
|
columns.forEach((column) => column.settle());
|
|
2100
|
-
|
|
2252
|
+
close2(columns.map((column) => column.index));
|
|
2101
2253
|
});
|
|
2102
2254
|
return {
|
|
2103
2255
|
result,
|
|
@@ -2435,19 +2587,19 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2435
2587
|
modal.appendChild(input);
|
|
2436
2588
|
}
|
|
2437
2589
|
const actions = element("div", "wxa-modal-actions");
|
|
2438
|
-
const
|
|
2590
|
+
const close2 = (confirm2) => {
|
|
2439
2591
|
wrapper.remove();
|
|
2440
2592
|
resolve({ confirm: confirm2, cancel: !confirm2, ...options.editable ? { content: input.value } : {} });
|
|
2441
2593
|
};
|
|
2442
2594
|
if (options.showCancel !== false) {
|
|
2443
2595
|
const cancel = element("button", "wxa-modal-cancel", options.cancelText || "\u53D6\u6D88");
|
|
2444
2596
|
cancel.style.color = options.cancelColor || "#000";
|
|
2445
|
-
cancel.addEventListener("click", () =>
|
|
2597
|
+
cancel.addEventListener("click", () => close2(false));
|
|
2446
2598
|
actions.appendChild(cancel);
|
|
2447
2599
|
}
|
|
2448
2600
|
const confirm = element("button", "wxa-modal-confirm", options.confirmText || "\u786E\u5B9A");
|
|
2449
2601
|
confirm.style.color = options.confirmColor || "#576b95";
|
|
2450
|
-
confirm.addEventListener("click", () =>
|
|
2602
|
+
confirm.addEventListener("click", () => close2(true));
|
|
2451
2603
|
actions.appendChild(confirm);
|
|
2452
2604
|
modal.appendChild(actions);
|
|
2453
2605
|
wrapper.appendChild(modal);
|
|
@@ -2459,7 +2611,7 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2459
2611
|
const wrapper = document.createElement("div");
|
|
2460
2612
|
const mask = maskElement(true);
|
|
2461
2613
|
const sheet = element("div", "wxa-actionsheet");
|
|
2462
|
-
const
|
|
2614
|
+
const close2 = (index) => {
|
|
2463
2615
|
wrapper.remove();
|
|
2464
2616
|
resolve(index);
|
|
2465
2617
|
};
|
|
@@ -2467,13 +2619,13 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2467
2619
|
options.itemList.forEach((text, index) => {
|
|
2468
2620
|
const button = element("button", "wxa-actionsheet-item", text);
|
|
2469
2621
|
button.style.color = options.itemColor || "#000";
|
|
2470
|
-
button.addEventListener("click", () =>
|
|
2622
|
+
button.addEventListener("click", () => close2(index));
|
|
2471
2623
|
sheet.appendChild(button);
|
|
2472
2624
|
});
|
|
2473
2625
|
const cancel = element("button", "wxa-actionsheet-cancel", "\u53D6\u6D88");
|
|
2474
|
-
cancel.addEventListener("click", () =>
|
|
2626
|
+
cancel.addEventListener("click", () => close2(null));
|
|
2475
2627
|
sheet.appendChild(cancel);
|
|
2476
|
-
mask.addEventListener("click", () =>
|
|
2628
|
+
mask.addEventListener("click", () => close2(null));
|
|
2477
2629
|
wrapper.append(mask, sheet);
|
|
2478
2630
|
this.overlay.appendChild(wrapper);
|
|
2479
2631
|
});
|
|
@@ -2494,10 +2646,10 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2494
2646
|
notice.setAttribute("role", "alert");
|
|
2495
2647
|
const text = element("div", "wxa-notice-text");
|
|
2496
2648
|
text.append(element("div", "wxa-notice-title", title), element("div", "wxa-notice-message", message));
|
|
2497
|
-
const
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
notice.append(element("span", "wxa-notice-icon", "!"), text,
|
|
2649
|
+
const close2 = element("button", "wxa-notice-close", "\xD7");
|
|
2650
|
+
close2.setAttribute("aria-label", "\u5173\u95ED");
|
|
2651
|
+
close2.addEventListener("click", () => this.hideNotice());
|
|
2652
|
+
notice.append(element("span", "wxa-notice-icon", "!"), text, close2);
|
|
2501
2653
|
this.stage.appendChild(notice);
|
|
2502
2654
|
this.noticeEl = notice;
|
|
2503
2655
|
this.noticeTimer = setTimeout(() => this.hideNotice(), NOTICE_DURATION);
|
|
@@ -2553,8 +2705,6 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2553
2705
|
this.api = new ApiRegistry((context) => this.reportUnimplemented(context));
|
|
2554
2706
|
/** setup 和测试 API 声明的请求拦截 */
|
|
2555
2707
|
this.routes = new RequestRoutes();
|
|
2556
|
-
/** 把被拦截的请求显示在 Network 面板里 */
|
|
2557
|
-
this.mockMirror = installMockMirror();
|
|
2558
2708
|
this.mapOperations = new MapOperations((webviewId, event, data) => this.publishToPages(event, data, [webviewId]));
|
|
2559
2709
|
this.service = null;
|
|
2560
2710
|
/** 新版基础库的业务子上下文;旧版基础库业务代码直接在逻辑层 iframe 里 */
|
|
@@ -2570,6 +2720,7 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2570
2720
|
this.routeListeners = [];
|
|
2571
2721
|
/** 渲染层报来的 2d、webgl 画布,按编号记下所在页面和最近的位置,供 placeCanvas 认出逻辑层的画布元素 */
|
|
2572
2722
|
this.canvases = /* @__PURE__ */ new Map();
|
|
2723
|
+
this.mockMirror = installMockMirror(info.externalServiceWorker);
|
|
2573
2724
|
this.device = info.device;
|
|
2574
2725
|
this.forwarder = new ConsoleForwarder(
|
|
2575
2726
|
info.forwardConsole ?? false,
|
|
@@ -2580,6 +2731,11 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2580
2731
|
this.shell = new PhoneShell(root, info.device);
|
|
2581
2732
|
this.tabPaths = new Set((info.wxConfig.tabBar?.list || []).map((item) => stripHtml(item.pagePath)));
|
|
2582
2733
|
this.storage = new MiniProgramStorage(window.localStorage, info.appid);
|
|
2734
|
+
this.webViewWindows = info.webViewWindow ? new WebViewWindows(info.device, (webviewId) => this.currentPage()?.id === webviewId) : null;
|
|
2735
|
+
if (this.webViewWindows) {
|
|
2736
|
+
const windows = this.webViewWindows;
|
|
2737
|
+
window.addEventListener("pagehide", () => windows.closeAll());
|
|
2738
|
+
}
|
|
2583
2739
|
const tabBar = info.wxConfig.tabBar ? { ...info.wxConfig.tabBar, list: info.wxConfig.tabBar.list.map((item) => ({ ...item, pagePath: stripHtml(item.pagePath) })) } : void 0;
|
|
2584
2740
|
this.shell.setTabBar(tabBar, (pagePath) => this.enqueueRoute(() => this.switchTab(pagePath)));
|
|
2585
2741
|
this.shell.onBack(() => this.enqueueRoute(() => this.navigateBack(1)));
|
|
@@ -2849,11 +3005,12 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2849
3005
|
}
|
|
2850
3006
|
closePage(page, options = { keepTab: true }) {
|
|
2851
3007
|
if (options.keepTab && this.tabPaths.has(page.path) && this.tabPages.get(page.path) === page) {
|
|
2852
|
-
|
|
3008
|
+
this.hidePage(page);
|
|
2853
3009
|
return;
|
|
2854
3010
|
}
|
|
2855
3011
|
if (this.tabPages.get(page.path) === page) this.tabPages.delete(page.path);
|
|
2856
3012
|
this.pages.delete(page.id);
|
|
3013
|
+
this.webViewWindows?.pageDestroyed(page.id);
|
|
2857
3014
|
page.destroy();
|
|
2858
3015
|
for (const [canvasNumber, record] of this.canvases) {
|
|
2859
3016
|
if (record.webviewId === page.id) this.canvases.delete(canvasNumber);
|
|
@@ -2861,9 +3018,10 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2861
3018
|
}
|
|
2862
3019
|
activate(page, openType) {
|
|
2863
3020
|
for (const other of this.pages.values()) {
|
|
2864
|
-
if (other !== page)
|
|
3021
|
+
if (other !== page) this.hidePage(other);
|
|
2865
3022
|
}
|
|
2866
3023
|
page.show();
|
|
3024
|
+
this.webViewWindows?.pageShown(page.id);
|
|
2867
3025
|
page.navigation = { ...page.navigation, showBack: this.stack.size > 1 };
|
|
2868
3026
|
this.shell.setNavigation(page.navigation);
|
|
2869
3027
|
this.shell.renderTabBar(this.tabPaths.has(page.path) ? page.path : null);
|
|
@@ -2876,6 +3034,14 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2876
3034
|
}, ROUTE_DONE_DELAY);
|
|
2877
3035
|
this.routeListeners.forEach((listener) => listener(page, openType));
|
|
2878
3036
|
}
|
|
3037
|
+
hidePage(page) {
|
|
3038
|
+
page.hide();
|
|
3039
|
+
this.webViewWindows?.pageHidden(page.id);
|
|
3040
|
+
}
|
|
3041
|
+
/** 页面里设置过 src 的 web-view,按创建顺序 */
|
|
3042
|
+
webViewsOf(page) {
|
|
3043
|
+
return this.webViewWindows ? this.webViewWindows.list(page.id) : iframeWebViews(page.win?.document);
|
|
3044
|
+
}
|
|
2879
3045
|
/** 宿主地址栏同步为当前页面,刷新后可回到同一页面 */
|
|
2880
3046
|
updateLocation(page) {
|
|
2881
3047
|
const params = new URLSearchParams(location.search);
|
|
@@ -2996,7 +3162,8 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
|
|
|
2996
3162
|
}),
|
|
2997
3163
|
...createWebViewApis({
|
|
2998
3164
|
documentOf: (webviewId) => this.pages.get(webviewId)?.win?.document,
|
|
2999
|
-
emitToWebview: (webviewId, event, data) => this.emitToWebview(webviewId, event, data)
|
|
3165
|
+
emitToWebview: (webviewId, event, data) => this.emitToWebview(webviewId, event, data),
|
|
3166
|
+
windows: this.webViewWindows
|
|
3000
3167
|
}),
|
|
3001
3168
|
...createMiscApis(this.info.appid, {
|
|
3002
3169
|
devtoolsLogin: this.info.devtoolsLogin,
|
|
@@ -3355,6 +3522,10 @@ ${script}
|
|
|
3355
3522
|
ready,
|
|
3356
3523
|
currentPage: () => snapshot(host.currentPage()),
|
|
3357
3524
|
pageStack: () => host.pageStack().map((page) => snapshot(page)),
|
|
3525
|
+
webViews: () => {
|
|
3526
|
+
const page = host.currentPage();
|
|
3527
|
+
return page ? host.webViewsOf(page) : [];
|
|
3528
|
+
},
|
|
3358
3529
|
waitForPage(path, timeout = 1e4) {
|
|
3359
3530
|
const target = path.replace(/^\//, "");
|
|
3360
3531
|
return new Promise((resolve, reject) => {
|
|
@@ -3418,13 +3589,14 @@ ${script}
|
|
|
3418
3589
|
const root = document.getElementById("wxa-root");
|
|
3419
3590
|
const info = await (await fetch("/__wxa__/app-info.json")).json();
|
|
3420
3591
|
const restore = new PageStackRestore(info.appid);
|
|
3421
|
-
const sendReport = connectDevServer(restore);
|
|
3592
|
+
const sendReport = info.liveReload === false ? () => void 0 : connectDevServer(restore);
|
|
3422
3593
|
if (info.buildError) {
|
|
3423
3594
|
new PhoneShell(root, info.device).showError(`\u7F16\u8BD1\u5931\u8D25
|
|
3424
3595
|
|
|
3425
3596
|
${info.buildError}`);
|
|
3426
3597
|
return;
|
|
3427
3598
|
}
|
|
3599
|
+
if (window.__wxa_webview_window__ === true) info.webViewWindow = true;
|
|
3428
3600
|
const host = new Host(info, root, sendReport);
|
|
3429
3601
|
window.__wxaHost = host;
|
|
3430
3602
|
let markReady;
|