Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/chrome-extension-mock/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export default class MockTab {

create(createProperties: chrome.tabs.CreateProperties, callback?: (tab: chrome.tabs.Tab) => void) {
this.hook.emit("create", createProperties);
callback?.({
id: 1,
} as chrome.tabs.Tab);
const tab = { id: 1 } as chrome.tabs.Tab;
callback?.(tab);
return Promise.resolve(tab);
}

remove(tabId: number) {
Expand Down
11 changes: 7 additions & 4 deletions src/pages/components/ScriptMenuList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type {
ScriptMenuItemOption,
} from "@App/app/service/service_worker/types";
import { popupClient, runtimeClient, scriptClient } from "@App/pages/store/features/script";
import { openInCurrentTab } from "@App/pkg/utils/utils";
import { i18nName } from "@App/locales/locales";

// 用于读取 metadata
Expand Down Expand Up @@ -245,8 +246,9 @@ const ListMenuItem = React.memo(
className="tw-text-left"
type="secondary"
icon={<IconEdit />}
onClick={() => {
window.open(`/src/options.html#/script/editor/${item.uuid}`, "_blank");
onClick={async () => {
// 经由扩展 API 打开,兼容 Edge Android(移动端 window.open 打不开内部页,#686)
await openInCurrentTab(`/src/options.html#/script/editor/${item.uuid}`);
window.close();
}}
>
Expand Down Expand Up @@ -297,8 +299,9 @@ const ListMenuItem = React.memo(
key="config"
type="secondary"
icon={<IconSettings />}
onClick={() => {
window.open(`/src/options.html#/?userConfig=${item.uuid}`, "_blank");
onClick={async () => {
// 经由扩展 API 打开,兼容 Edge Android(移动端 window.open 打不开内部页,#686)
await openInCurrentTab(`/src/options.html#/?userConfig=${item.uuid}`);
window.close();
}}
>
Expand Down
8 changes: 4 additions & 4 deletions src/pages/components/layout/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import "./index.css";
import { arcoLocale } from "@App/locales/arco";
import { prepareScriptByCode } from "@App/pkg/utils/script";
import { saveHandle } from "@App/pkg/utils/filehandle-db";
import { makeBlobURL } from "@App/pkg/utils/utils";
import { makeBlobURL, openInCurrentTab } from "@App/pkg/utils/utils";
import ScrollBoundary from "@App/pages/components/layout/ScrollBoundary";

// --- 工具函数移出组件外,避免每次 Render 重新定义 ---
Expand Down Expand Up @@ -244,9 +244,9 @@ const MainLayout: React.FC<{
}
const fid = checkOk[1].value;
await saveHandle(fid, fileHandle); // fileHandle以DB方式传送至安装页面
// 打开安装页面
const installWindow = window.open(`/src/install.html?file=${fid}`, "_blank");
if (!installWindow) {
// 打开安装页面(经由扩展 API,兼容 Edge Android —— 移动端 window.open 打不开内部页,#686)
const installTab = await openInCurrentTab(`/src/install.html?file=${fid}`);
if (!installTab) {
throw new Error(t("install_page_open_failed"));
}
stat.success++;
Expand Down
6 changes: 3 additions & 3 deletions src/pages/options/routes/Tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { useSystemConfig } from "./utils";
import { uuidv4 } from "@App/pkg/utils/uuid";
import { cacheInstance } from "@App/app/cache";
import { CACHE_KEY_IMPORT_FILE } from "@App/app/cache_key";
import { makeBlobURL } from "@App/pkg/utils/utils";
import { makeBlobURL, openInCurrentTab } from "@App/pkg/utils/utils";

const openImportWindow = async (filename: string, file: Blob) => {
// 打开导入窗口,用cache实现数据交互
Expand All @@ -39,8 +39,8 @@ const openImportWindow = async (filename: string, file: Blob) => {
filename: filename,
url: url,
});
// 打开导入窗口,用cache实现数据交互
window.open(chrome.runtime.getURL(`/src/import.html?uuid=${uuid}`), "_blank");
// 打开导入窗口,用cache实现数据交互(经由扩展 API,兼容 Edge Android)
await openInCurrentTab(`/src/import.html?uuid=${uuid}`);
};

function Tools() {
Expand Down
10 changes: 10 additions & 0 deletions src/pages/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
min-height: 150px;
max-height: 500px;
}
/* 桌面端 popup 的视口宽度恒等于 body 宽度(320px),永远不会命中此查询,行为不变;
移动端(如 Edge Android)popup 被强制撑满设备宽度(≥360px),命中后填满外层容器,
消除右侧留白(#686)。阈值取 340px:高于桌面 320px、低于最小手机宽度。 */
@media (min-width: 340px) {
html,
body {
width: 100%;
max-height: none;
}
}
</style>
</head>

Expand Down
9 changes: 5 additions & 4 deletions src/pages/popup/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { popupClient, requestOpenBatchUpdatePage } from "@App/pages/store/featur
import type { ScriptMenu, TPopupScript } from "@App/app/service/service_worker/types";
import { systemConfig } from "@App/pages/store/global";
import { isChineseUser, localePath } from "@App/locales/locales";
import { getCurrentTab } from "@App/pkg/utils/utils";
import { getCurrentTab, openInCurrentTab } from "@App/pkg/utils/utils";
import { subscribeMessage } from "@App/pages/store/global";
import type { TDeleteScript, TEnableScript, TScriptRunStatus } from "@App/app/service/queue";
import { SCRIPT_RUN_STATUS_RUNNING } from "@App/app/repo/scripts";
Expand Down Expand Up @@ -309,8 +309,9 @@ function App() {
systemConfig.setEnableScript(val);
},
handleSettingsClick: () => {
// 使用 window.open 而非 <a> 连结:避免 Vivaldi 等浏览器偶发崩溃
window.open("/src/options.html", "_blank");
// 经由扩展 API 打开(而非 window.open / <a>):既避免 Vivaldi 偶发崩溃,
// 也兼容 Edge Android —— 移动端 window.open 打不开 chrome-extension:// 内部页(#686)
openInCurrentTab("/src/options.html");
},
handleNotificationClick: () => {
setShowAlert((prev) => !prev);
Expand Down Expand Up @@ -341,7 +342,7 @@ function App() {
await chrome.storage.local.set({
activeTabUrl: { url: currentUrl },
});
window.open("/src/options.html#/script/editor?target=initial", "_blank");
await openInCurrentTab("/src/options.html#/script/editor?target=initial");
break;
case "checkUpdate":
requestOpenBatchUpdatePage(getUrlDomain(currentUrl));
Expand Down
27 changes: 27 additions & 0 deletions src/pkg/utils/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
cleanFileName,
formatBytes,
normalizeResponseHeaders,
openInCurrentTab,
stringMatching,
stripUndefined,
toCamelCase,
Expand Down Expand Up @@ -704,3 +705,29 @@ describe("stripUndefined", () => {
expect(result).toEqual({ a: [1, 2, 3] });
});
});

describe("openInCurrentTab", () => {
// 在 Edge Android 等移动端,window.open 打不开 chrome-extension:// 内部页,
// 内部页必须经由扩展 API(chrome.tabs.create)打开(见 #686)。
it("应通过 chrome.tabs.create 在当前标签页之后打开内部页", async () => {
let created: chrome.tabs.CreateProperties | undefined;
const onCreate = (props: chrome.tabs.CreateProperties) => {
created = props;
};
(chrome.tabs as any).hook.on("create", onCreate);
try {
await openInCurrentTab("/src/options.html");
} finally {
(chrome.tabs as any).hook.removeListener("create", onCreate);
}
expect(created?.url).toBe("/src/options.html");
// getCurrentTab 返回 index:0 的标签,新标签应排在其后
expect(created?.index).toBe(1);
});

// MainLayout 拖拽导入据返回值判断是否成功打开安装页,因此必须回传创建出来的标签
it("应返回创建出来的标签供调用方判断是否成功打开", async () => {
const tab = await openInCurrentTab("/src/install.html?file=abc");
expect(tab?.id).toBe(1);
});
});
9 changes: 4 additions & 5 deletions src/pkg/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export async function getTab(tabId: number) {
}

// 在当前页后打开一个新页面,如果指定tabId则在该tab后打开
export async function openInCurrentTab(url: string, tabId?: number) {
export async function openInCurrentTab(url: string, tabId?: number): Promise<chrome.tabs.Tab | undefined> {
const tab = await (tabId ? getTab(tabId) : getCurrentTab());
const createProperties: chrome.tabs.CreateProperties = { url };
if (tab) {
Expand All @@ -128,20 +128,19 @@ export async function openInCurrentTab(url: string, tabId?: number) {
}
// 先尝试以 openerTabId 和 windowId 打开
try {
await chrome.tabs.create(createProperties);
return;
return await chrome.tabs.create(createProperties);
} catch (e: any) {
console.error("Error opening tab:", e);
}
// 失败的话,删去 openerTabId 和 windowId ,再次尝试打开
delete createProperties.openerTabId;
delete createProperties.windowId;
try {
await chrome.tabs.create(createProperties);
return;
return await chrome.tabs.create(createProperties);
} catch (e: any) {
console.error("Retry opeing tab error:", e);
}
return undefined;
}

// 检查订阅规则是否改变,是否能够静默更新
Expand Down
Loading