Skip to content

Commit 7f30198

Browse files
cyfung1031CodFrm
andauthored
🐛 恢复 GM_openInTab 的 useOpen 选项 #1043 (#1044)
* fix #1043 * mExtScheme * vitest * 还是用 useOpen 了 * Update gm_api.ts * 修改注释说明 * 修改注释说明 * 修改注释说明 * 修改注释说明 * 修改注释说明 * Update gm_api.ts * 修改注释 * Update gm_api.ts * typescript fix * 根据copilot意见修改 * Update gm_api.ts --------- Co-authored-by: 王一之 <yz@ggnb.top>
1 parent 4f2deda commit 7f30198

5 files changed

Lines changed: 85 additions & 12 deletions

File tree

packages/message/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class SenderRuntime {
100100
}
101101
}
102102

103-
type ApiFunction = (params: any, con: IGetSender) => Promise<any> | void;
103+
type ApiFunction = (params: any, con: IGetSender) => Promise<any> | any | void;
104104
type ApiFunctionSync = (params: any, con: IGetSender) => any;
105105
type MiddlewareFunction = (params: any, con: IGetSender, next: () => Promise<any> | any) => Promise<any> | any;
106106

src/app/service/offscreen/gm_api.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { BgGMXhr } from "@App/pkg/utils/xhr/bg_gm_xhr";
22
import type { IGetSender, Group } from "@Packages/message/server";
33

4+
// nativePageXHR 不需要绑定 Offscreen.GMApi 的 this,外部可以直接引用
5+
export const nativePageXHR = async (details: GMSend.XHRDetails, sender: IGetSender) => {
6+
const con = sender.getConnect(); // con can be undefined
7+
if (!con) throw new Error("offscreen xmlHttpRequest: Connection is undefined");
8+
const bgGmXhr = new BgGMXhr(details, { statusCode: 0, finalUrl: "", responseHeaders: "" }, con);
9+
bgGmXhr.do();
10+
};
11+
12+
// nativePageWindowOpen 不需要绑定 Offscreen.GMApi 的 this,外部可以直接引用
13+
export const nativePageWindowOpen = (details: { url: string }): boolean => {
14+
if (!details || !details.url) throw new Error("offscreen window.open: details.url is undefined");
15+
return !!window.open(details.url);
16+
};
17+
418
export default class GMApi {
519
constructor(private group: Group) {}
620

7-
async xmlHttpRequest(details: GMSend.XHRDetails, sender: IGetSender) {
8-
const con = sender.getConnect(); // con can be undefined
9-
if (!con) throw new Error("offscreen xmlHttpRequest: Connection is undefined");
10-
const bgGmXhr = new BgGMXhr(details, { statusCode: 0, finalUrl: "", responseHeaders: "" }, con);
11-
bgGmXhr.do();
12-
}
13-
1421
textarea: HTMLTextAreaElement = document.createElement("textarea");
1522

1623
clipboardData: { type?: string; data: string } | undefined;
@@ -37,7 +44,8 @@ export default class GMApi {
3744
this.clipboardData = undefined;
3845
});
3946

40-
this.group.on("xmlHttpRequest", this.xmlHttpRequest.bind(this));
47+
this.group.on("xmlHttpRequest", nativePageXHR);
48+
this.group.on("windowOpen", nativePageWindowOpen);
4149
this.group.on("setClipboard", this.setClipboard.bind(this));
4250
}
4351
}

src/app/service/service_worker/gm_api/gm_api.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { ConfirmParam } from "../permission_verify";
1010
import PermissionVerify, { PermissionVerifyApiGet } from "../permission_verify";
1111
import { cacheInstance } from "@App/app/cache";
1212
import { type RuntimeService } from "../runtime";
13-
import { getIcon, isFirefox, openInCurrentTab, cleanFileName } from "@App/pkg/utils/utils";
13+
import { getIcon, isFirefox, getCurrentTab, openInCurrentTab, cleanFileName } from "@App/pkg/utils/utils";
1414
import { type SystemConfig } from "@App/pkg/config/config";
1515
import i18next, { i18nName } from "@App/locales/locales";
1616
import FileSystemFactory from "@Packages/filesystem/factory";
@@ -43,6 +43,7 @@ import {
4343
} from "./gm_xhr";
4444
import { headerModifierMap, headersReceivedMap } from "./gm_xhr";
4545
import { BgGMXhr } from "@App/pkg/utils/xhr/bg_gm_xhr";
46+
import { nativePageWindowOpen } from "../../offscreen/gm_api";
4647

4748
let generatedUniqueMarkerIDs = "";
4849
let generatedUniqueMarkerIDWhen = "";
@@ -912,6 +913,28 @@ export default class GMApi {
912913
async GM_openInTab(request: GMApiRequest<[string, GMTypes.SWOpenTabOptions]>, sender: IGetSender) {
913914
const url = request.params[0];
914915
const options = request.params[1];
916+
if (options.useOpen) {
917+
const prevTab = await getCurrentTab();
918+
// 发送给offscreen页面处理 (使用window.open)
919+
let ok;
920+
if (typeof window === "object" && typeof window?.open === "function") {
921+
// Firefox Background Page
922+
ok = nativePageWindowOpen({ url });
923+
} else {
924+
ok = await sendMessage(this.msgSender, "offscreen/gmApi/windowOpen", { url });
925+
}
926+
// 注:一般而言,特殊打开的话没有实际 tab id.
927+
// ------------------------------------------
928+
if (ok) {
929+
// 由于window.open强制在前台打开标签,因此获取状态为 { active:true } 的标签即为新标签
930+
const tab = await getCurrentTab();
931+
const tabId = tab?.id;
932+
if (tabId && tabId !== prevTab?.id) return tabId;
933+
}
934+
// 当新tab被浏览器阻止时 window.open() 会返回 null 视为已经关闭
935+
// 似乎在Firefox中禁止在background页面使用window.open(),强制返回null
936+
return false;
937+
}
915938
const getNewTabId = async () => {
916939
const { tabId, windowId } = sender.getExtMessageSender();
917940
const active = options.active;

src/template/scriptcat.d.tpl

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,34 @@ declare namespace GMTypes {
462462
* 默认值:false
463463
*/
464464
pinned?: boolean;
465+
466+
/**
467+
* 使用 `window.open` 打开新标签,而不是 `chrome.tabs.create`
468+
* 在打开一些特殊协议的链接时很有用,例如 `vscode://`, `m3u8dl://`
469+
* 其他参数在这个打开方式下无效
470+
*
471+
* 相关:Issue #178 #1043
472+
* 默认值:false
473+
*/
474+
useOpen?: boolean;
465475
}
466476

467477
type SWOpenTabOptions = OpenTabOptions & Required<Pick<OpenTabOptions, "active">>;
468478

479+
/**
480+
* XMLHttpRequest readyState 状态值
481+
* @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
482+
*/
483+
type ReadyState =
484+
| 0 // UNSENT
485+
| 1 // OPENED
486+
| 2 // HEADERS_RECEIVED
487+
| 3 // LOADING
488+
| 4; // DONE
489+
469490
interface XHRResponse {
470491
finalUrl?: string;
471-
readyState?: 0 | 1 | 2 | 3 | 4;
492+
readyState?: ReadyState;
472493
responseHeaders?: string;
473494
status?: number;
474495
statusText?: string;
@@ -557,7 +578,14 @@ declare namespace GMTypes {
557578
// TM/SC 标准回调
558579
onload?: Listener<object>;
559580
onerror?: Listener<DownloadError>;
560-
onprogress?: Listener<XHRProgress>;
581+
onprogress?: Listener<{
582+
done: number;
583+
lengthComputable: boolean;
584+
loaded: number;
585+
position?: number;
586+
total: number;
587+
totalSize: number;
588+
}>;
561589
ontimeout?: (arg1?: any) => void;
562590
}
563591

src/types/scriptcat.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,24 @@ declare namespace GMTypes {
462462
* 默认值:false
463463
*/
464464
pinned?: boolean;
465+
466+
/**
467+
* 使用 `window.open` 打开新标签,而不是 `chrome.tabs.create`
468+
* 在打开一些特殊协议的链接时很有用,例如 `vscode://`, `m3u8dl://`
469+
* 其他参数在这个打开方式下无效
470+
*
471+
* 相关:Issue #178 #1043
472+
* 默认值:false
473+
*/
474+
useOpen?: boolean;
465475
}
466476

467477
type SWOpenTabOptions = OpenTabOptions & Required<Pick<OpenTabOptions, "active">>;
468478

479+
/**
480+
* XMLHttpRequest readyState 状态值
481+
* @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
482+
*/
469483
type ReadyState =
470484
| 0 // UNSENT
471485
| 1 // OPENED

0 commit comments

Comments
 (0)