popup页面
Some checks failed
build / Build (push) Failing after 7s
test / Run tests (push) Failing after 8s
Some checks failed
build / Build (push) Failing after 7s
test / Run tests (push) Failing after 8s
This commit is contained in:
@ -116,7 +116,6 @@ export class Group {
|
||||
// 转发消息
|
||||
export function forwardMessage(prefix: string, path: string, from: Server, to: MessageSend, middleware?: ApiFunction) {
|
||||
from.on(path, async (params, fromCon) => {
|
||||
console.log("forwardMessage", path, prefix, params);
|
||||
if (middleware) {
|
||||
const resp = await middleware(params, new GetSender(fromCon));
|
||||
if (resp !== false) {
|
||||
|
@ -152,7 +152,7 @@ export default defineConfig({
|
||||
}),
|
||||
new rspack.HtmlRspackPlugin({
|
||||
filename: `${dist}/ext/src/popup.html`,
|
||||
template: `${src}/pages/popup/index.html`,
|
||||
template: `${src}/pages/popup.html`,
|
||||
inject: "head",
|
||||
title: "Home - ScriptCat",
|
||||
minify: true,
|
||||
|
@ -8,6 +8,7 @@ import { connect } from "@Packages/message/client";
|
||||
import Cache, { incr } from "@App/app/cache";
|
||||
import { unsafeHeaders } from "@App/runtime/utils";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
|
||||
// GMApi,处理脚本的GM API调用请求
|
||||
|
||||
@ -35,6 +36,7 @@ export default class GMApi {
|
||||
constructor(
|
||||
private group: Group,
|
||||
private send: MessageSend,
|
||||
private mq: MessageQueue,
|
||||
private value: ValueService
|
||||
) {
|
||||
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
|
||||
@ -83,7 +85,6 @@ export default class GMApi {
|
||||
async buildDNRRule(reqeustId: number, params: GMSend.XHRDetails): Promise<{ [key: string]: string }> {
|
||||
// 检查是否有unsafe header,有则生成dnr规则
|
||||
const headers = params.headers;
|
||||
console.log(headers, !headers);
|
||||
if (!headers) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
@ -181,12 +182,42 @@ export default class GMApi {
|
||||
});
|
||||
}
|
||||
|
||||
start() {
|
||||
this.group.on("gmApi", this.handlerRequest.bind(this));
|
||||
@PermissionVerify.API()
|
||||
GM_registerMenuCommand(request: Request, con: GetSender) {
|
||||
console.log("registerMenuCommand", request.params);
|
||||
const [id, name, accessKey] = request.params;
|
||||
// 触发菜单注册, 在popup中处理
|
||||
this.mq.emit("registerMenuCommand", {
|
||||
uuid: request.script.uuid,
|
||||
id: id,
|
||||
name: name,
|
||||
accessKey: accessKey,
|
||||
con: con.getConnect(),
|
||||
});
|
||||
con.getConnect().onDisconnect(() => {
|
||||
// 取消注册
|
||||
this.mq.emit("unregisterMenuCommand", {
|
||||
uuid: request.script.uuid,
|
||||
name: name,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@PermissionVerify.API()
|
||||
GM_unregisterMenuCommand(request: Request) {
|
||||
const [id] = request.params;
|
||||
// 触发菜单取消注册, 在popup中处理
|
||||
this.mq.emit("unregisterMenuCommand", {
|
||||
uuid: request.script.uuid,
|
||||
id: id,
|
||||
});
|
||||
}
|
||||
|
||||
// 处理GM_xmlhttpRequest请求
|
||||
handlerGmXhr() {
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
(details) => {
|
||||
if (details.tabId === -1) {
|
||||
console.log(details);
|
||||
// 判断是否存在X-Scriptcat-GM-XHR-Request-Id
|
||||
// 讲请求id与chrome.webRequest的请求id关联
|
||||
if (details.requestHeaders) {
|
||||
@ -228,4 +259,9 @@ export default class GMApi {
|
||||
["responseHeaders", "extraHeaders"]
|
||||
);
|
||||
}
|
||||
|
||||
start() {
|
||||
this.group.on("gmApi", this.handlerRequest.bind(this));
|
||||
this.handlerGmXhr();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { ResourceService } from "./resource";
|
||||
import { ValueService } from "./value";
|
||||
import { RuntimeService } from "./runtime";
|
||||
import { ServiceWorkerMessageSend } from "@Packages/message/window_message";
|
||||
import { PopupService } from "./popup";
|
||||
|
||||
export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode";
|
||||
|
||||
@ -31,5 +32,7 @@ export default class ServiceWorkerManager {
|
||||
script.init();
|
||||
const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value, script);
|
||||
runtime.init();
|
||||
const popup = new PopupService(this.api.group("popup"), this.mq, runtime);
|
||||
popup.init();
|
||||
}
|
||||
}
|
||||
|
26
src/app/service/service_worker/popup.ts
Normal file
26
src/app/service/service_worker/popup.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
import { GetSender, Group } from "@Packages/message/server";
|
||||
import { RuntimeService } from "./runtime";
|
||||
|
||||
// 处理popup页面的数据
|
||||
export class PopupService {
|
||||
constructor(
|
||||
private group: Group,
|
||||
private mq: MessageQueue,
|
||||
private runtime: RuntimeService
|
||||
) {}
|
||||
|
||||
registerMenuCommand(message: { uuid: string; id: string; name: string; accessKey: string; con: GetSender }) {
|
||||
console.log("registerMenuCommand", message);
|
||||
}
|
||||
|
||||
unregisterMenuCommand(message: { id: string }) {
|
||||
console.log("unregisterMenuCommand", message);
|
||||
}
|
||||
|
||||
init() {
|
||||
// 处理脚本菜单数据
|
||||
this.mq.subscribe("registerMenuCommand", this.registerMenuCommand.bind(this));
|
||||
this.mq.subscribe("unregisterMenuCommand", this.unregisterMenuCommand.bind(this));
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ export class RuntimeService {
|
||||
|
||||
async init() {
|
||||
// 启动gm api
|
||||
const gmApi = new GMApi(this.group, this.sender, this.value);
|
||||
const gmApi = new GMApi(this.group, this.sender, this.mq, this.value);
|
||||
gmApi.start();
|
||||
|
||||
this.group.on("stopScript", this.stopScript.bind(this));
|
||||
@ -238,6 +238,15 @@ export class RuntimeService {
|
||||
this.saveScriptMatchInfo();
|
||||
}
|
||||
|
||||
async deleteScriptMatch(uuid: string) {
|
||||
if (!this.scriptMatchCache) {
|
||||
await this.loadScriptMatchInfo();
|
||||
}
|
||||
this.scriptMatchCache!.delete(uuid);
|
||||
this.scriptMatch.del(uuid);
|
||||
this.saveScriptMatchInfo();
|
||||
}
|
||||
|
||||
async registryPageScript(script: Script) {
|
||||
if (await Cache.getInstance().has("registryScript:" + script.uuid)) {
|
||||
return;
|
||||
|
@ -1,7 +1,5 @@
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import React, { useEffect, useState } from "react";
|
||||
import MessageInternal from "@App/app/message/internal";
|
||||
import { MessageSender } from "@App/app/message/message";
|
||||
import { ScriptMenu } from "@App/runtime/service_worker/runtime";
|
||||
import {
|
||||
Button,
|
||||
@ -21,13 +19,9 @@ import {
|
||||
IconMinus,
|
||||
IconSettings,
|
||||
} from "@arco-design/web-react/icon";
|
||||
import IoC from "@App/app/ioc";
|
||||
import ScriptController from "@App/app/service/script/controller";
|
||||
import { SCRIPT_RUN_STATUS_RUNNING } from "@App/app/repo/scripts";
|
||||
import { RiPlayFill, RiStopFill } from "react-icons/ri";
|
||||
import RuntimeController from "@App/runtime/content/runtime";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SystemConfig } from "@App/pkg/config/config";
|
||||
import { ScriptIcons } from "@App/pages/options/routes/utils";
|
||||
|
||||
const CollapseItem = Collapse.Item;
|
||||
@ -51,10 +45,6 @@ const ScriptMenuList: React.FC<{
|
||||
currentUrl: string;
|
||||
}> = ({ script, isBackscript, currentUrl }) => {
|
||||
const [list, setList] = useState([] as ScriptMenu[]);
|
||||
const message = IoC.instance(MessageInternal) as MessageInternal;
|
||||
const scriptCtrl = IoC.instance(ScriptController) as ScriptController;
|
||||
const runtimeCtrl = IoC.instance(RuntimeController) as RuntimeController;
|
||||
const systemConfig = IoC.instance(SystemConfig) as SystemConfig;
|
||||
const [expandMenuIndex, setExpandMenuIndex] = useState<{
|
||||
[key: string]: boolean;
|
||||
}>({});
|
||||
@ -70,23 +60,23 @@ const ScriptMenuList: React.FC<{
|
||||
setList(script);
|
||||
}, [script]);
|
||||
|
||||
useEffect(() => {
|
||||
// 监听脚本运行状态
|
||||
const channel = runtimeCtrl.watchRunStatus();
|
||||
channel.setHandler(([id, status]: any) => {
|
||||
setList((prev) => {
|
||||
const newList = [...prev];
|
||||
const index = newList.findIndex((item) => item.id === id);
|
||||
if (index !== -1) {
|
||||
newList[index].runStatus = status;
|
||||
}
|
||||
return newList;
|
||||
});
|
||||
});
|
||||
return () => {
|
||||
channel.disChannel();
|
||||
};
|
||||
}, []);
|
||||
// useEffect(() => {
|
||||
// // 监听脚本运行状态
|
||||
// const channel = runtimeCtrl.watchRunStatus();
|
||||
// channel.setHandler(([id, status]: any) => {
|
||||
// setList((prev) => {
|
||||
// const newList = [...prev];
|
||||
// const index = newList.findIndex((item) => item.id === id);
|
||||
// if (index !== -1) {
|
||||
// newList[index].runStatus = status;
|
||||
// }
|
||||
// return newList;
|
||||
// });
|
||||
// });
|
||||
// return () => {
|
||||
// channel.disChannel();
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
const sendMenuAction = (sender: MessageSender, channelFlag: string) => {
|
||||
let id = sender.tabId;
|
||||
|
@ -14,11 +14,8 @@
|
||||
padding: 0;
|
||||
border: 0;
|
||||
width: 320px;
|
||||
/* height: 500px; */
|
||||
min-height: 150px;
|
||||
max-height: 500px;
|
||||
/* overflow-y: auto; */
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
</style>
|
||||
</head>
|
@ -1,41 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a > .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
@ -1,31 +1,221 @@
|
||||
import { useState } from "react";
|
||||
import reactLogo from "@App/assets/logo.png";
|
||||
import "./App.css";
|
||||
import { ExtVersion } from "@App/app/const";
|
||||
import { Alert, Badge, Button, Card, Collapse, Dropdown, Menu, Switch } from "@arco-design/web-react";
|
||||
import {
|
||||
IconBook,
|
||||
IconBug,
|
||||
IconGithub,
|
||||
IconHome,
|
||||
IconMoreVertical,
|
||||
IconNotification,
|
||||
IconPlus,
|
||||
IconSearch,
|
||||
} from "@arco-design/web-react/icon";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { RiMessage2Line } from "react-icons/ri";
|
||||
import semver from "semver";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ScriptMenuList from "../components/ScriptMenuList";
|
||||
import { ScriptMenu } from "@App/runtime/service_worker/runtime";
|
||||
|
||||
const CollapseItem = Collapse.Item;
|
||||
|
||||
const iconStyle = {
|
||||
marginRight: 8,
|
||||
fontSize: 16,
|
||||
transform: "translateY(1px)",
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = useState(0);
|
||||
const [scriptList, setScriptList] = useState<ScriptMenu[]>([]);
|
||||
const [backScriptList, setBackScriptList] = useState<ScriptMenu[]>([]);
|
||||
const [showAlert, setShowAlert] = useState(false);
|
||||
const [notice, setNotice] = useState("");
|
||||
const [isRead, setIsRead] = useState(true);
|
||||
const [version, setVersion] = useState(ExtVersion);
|
||||
const [currentUrl, setCurrentUrl] = useState("");
|
||||
const [isEnableScript, setIsEnableScript] = useState(localStorage.enable_script !== "false");
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<div>
|
||||
<a href="https://reactjs.org" target="_blank" rel="noreferrer">
|
||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||
</a>
|
||||
</div>
|
||||
<h1>Rspack + React3 + TypeScript</h1>
|
||||
<div className="card">
|
||||
<button type="button" onClick={() => setCount(count => count + 1)}>
|
||||
count is {count}
|
||||
</button>
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to test HMR
|
||||
</p>
|
||||
</div>
|
||||
<p className="read-the-docs">
|
||||
Click on the Rspack and React logos to learn more
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
let url: URL | undefined;
|
||||
try {
|
||||
url = new URL(currentUrl);
|
||||
} catch (e) {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
// const message = IoC.instance(MessageInternal) as MessageInternal;
|
||||
// useEffect(() => {
|
||||
// systemManage.getNotice().then((res) => {
|
||||
// if (res) {
|
||||
// setNotice(res.notice);
|
||||
// setIsRead(res.isRead);
|
||||
// }
|
||||
// });
|
||||
// systemManage.getVersion().then((res) => {
|
||||
// res && setVersion(res);
|
||||
// });
|
||||
// chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
// if (!tabs.length) {
|
||||
// return;
|
||||
// }
|
||||
// setCurrentUrl(tabs[0].url || "");
|
||||
// message
|
||||
// .syncSend("queryPageScript", { url: tabs[0].url, tabId: tabs[0].id })
|
||||
// .then((resp: { scriptList: ScriptMenu[]; backScriptList: ScriptMenu[] }) => {
|
||||
// // 按照开启状态和更新时间排序
|
||||
// const list = resp.scriptList;
|
||||
// list.sort((a, b) => {
|
||||
// if (a.enable === b.enable) {
|
||||
// if (a.runNum !== b.runNum) {
|
||||
// return b.runNum - a.runNum;
|
||||
// }
|
||||
// return b.updatetime - a.updatetime;
|
||||
// }
|
||||
// return a.enable ? -1 : 1;
|
||||
// });
|
||||
// setScriptList(list);
|
||||
// setBackScriptList(resp.backScriptList);
|
||||
// });
|
||||
// });
|
||||
// }, []);
|
||||
return (
|
||||
<Card
|
||||
size="small"
|
||||
title={
|
||||
<div className="flex justify-between">
|
||||
<span className="text-xl">ScriptCat</span>
|
||||
<div className="flex flex-row items-center">
|
||||
<Switch
|
||||
size="small"
|
||||
checked={isEnableScript}
|
||||
onChange={(val) => {
|
||||
setIsEnableScript(val);
|
||||
if (val) {
|
||||
localStorage.enable_script = "true";
|
||||
} else {
|
||||
localStorage.enable_script = "false";
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<IconHome />}
|
||||
iconOnly
|
||||
onClick={() => {
|
||||
// 用a链接的方式,vivaldi竟然会直接崩溃
|
||||
window.open("/src/options.html", "_blank");
|
||||
}}
|
||||
/>
|
||||
<Badge count={isRead ? 0 : 1} dot offset={[-8, 6]}>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<IconNotification />}
|
||||
iconOnly
|
||||
onClick={() => {
|
||||
setShowAlert(!showAlert);
|
||||
setIsRead(true);
|
||||
systemManage.setRead(true);
|
||||
}}
|
||||
/>
|
||||
</Badge>
|
||||
<Dropdown
|
||||
droplist={
|
||||
<Menu
|
||||
style={{
|
||||
maxHeight: "none",
|
||||
}}
|
||||
onClickMenuItem={async (key) => {
|
||||
switch (key) {
|
||||
case "newScript":
|
||||
await chrome.storage.local.set({
|
||||
activeTabUrl: {
|
||||
url: currentUrl,
|
||||
},
|
||||
});
|
||||
window.open("/src/options.html#/script/editor?target=initial", "_blank");
|
||||
break;
|
||||
default:
|
||||
window.open(key, "_blank");
|
||||
break;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Menu.Item key="newScript">
|
||||
<IconPlus style={iconStyle} />
|
||||
{t("create_script")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key={`https://scriptcat.org/search?domain=${url && url.host}`}>
|
||||
<IconSearch style={iconStyle} />
|
||||
{t("get_script")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="https://github.com/scriptscat/scriptcat/issues">
|
||||
<IconBug style={iconStyle} />
|
||||
{t("report_issue")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="https://docs.scriptcat.org/">
|
||||
<IconBook style={iconStyle} />
|
||||
{t("project_docs")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="https://bbs.tampermonkey.net.cn/">
|
||||
<RiMessage2Line style={iconStyle} />
|
||||
{t("community")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="https://github.com/scriptscat/scriptcat">
|
||||
<IconGithub style={iconStyle} />
|
||||
GitHub
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
trigger="click"
|
||||
>
|
||||
<Button type="text" icon={<IconMoreVertical />} iconOnly />
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<Alert
|
||||
style={{ marginBottom: 20, display: showAlert ? "flex" : "none" }}
|
||||
type="info"
|
||||
// eslint-disable-next-line react/no-danger
|
||||
content={<div dangerouslySetInnerHTML={{ __html: notice }} />}
|
||||
/>
|
||||
<Collapse bordered={false} defaultActiveKey={["script", "background"]} style={{ maxWidth: 640 }}>
|
||||
<CollapseItem
|
||||
header={t("current_page_scripts")}
|
||||
name="script"
|
||||
style={{ padding: "0" }}
|
||||
contentStyle={{ padding: "0" }}
|
||||
>
|
||||
<ScriptMenuList script={scriptList} isBackscript={false} currentUrl={currentUrl} />
|
||||
</CollapseItem>
|
||||
|
||||
<CollapseItem
|
||||
header={t("enabled_background_scripts")}
|
||||
name="background"
|
||||
style={{ padding: "0" }}
|
||||
contentStyle={{ padding: "0" }}
|
||||
>
|
||||
<ScriptMenuList script={backScriptList} isBackscript currentUrl={currentUrl} />
|
||||
</CollapseItem>
|
||||
</Collapse>
|
||||
<div className="flex flex-row arco-card-header !h-6">
|
||||
<span className="text-[12px] font-500">{`v${ExtVersion}`}</span>
|
||||
{semver.lt(ExtVersion, version) && (
|
||||
<span
|
||||
onClick={() => {
|
||||
window.open(`https://github.com/scriptscat/scriptcat/releases/tag/v${version}`);
|
||||
}}
|
||||
className="text-1 font-500"
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
{t("popup.new_version_available")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
@ -1,70 +1,19 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
.arco-collapse-item-header-title {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
.arco-collapse-item-header-title .arco-space {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
.arco-space-item:last-child {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
.arco-collapse {
|
||||
border-bottom: 1px solid var(--color-neutral-3) !important;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.arco-collapse-item {
|
||||
border: 0;
|
||||
}
|
||||
|
@ -1,10 +1,36 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
import LoggerCore from "@App/app/logger/core.ts";
|
||||
import migrate from "@App/app/migrate.ts";
|
||||
import { LoggerDAO } from "@App/app/repo/logger.ts";
|
||||
import DBWriter from "@App/app/logger/db_writer.ts";
|
||||
import "@arco-design/web-react/dist/css/arco.css";
|
||||
import "@App/locales/locales";
|
||||
import "@App/index.css";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "../store/store.ts";
|
||||
|
||||
// 初始化数据库
|
||||
migrate();
|
||||
// 初始化日志组件
|
||||
const loggerCore = new LoggerCore({
|
||||
writer: new DBWriter(new LoggerDAO()),
|
||||
labels: { env: "install" },
|
||||
});
|
||||
|
||||
loggerCore.logger().debug("page start");
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<div
|
||||
style={{
|
||||
borderBottom: "1px solid var(--color-neutral-3)",
|
||||
}}
|
||||
>
|
||||
<App />
|
||||
</div>
|
||||
</Provider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
@ -11,20 +11,13 @@ export default class ContentRuntime {
|
||||
) {}
|
||||
|
||||
start(scripts: ScriptRunResouce[]) {
|
||||
this.msg.onMessage((msg, sendResponse) => {
|
||||
console.log("content onMessage", msg);
|
||||
});
|
||||
this.msg.onConnect((msg, connect) => {
|
||||
console.log(msg, connect);
|
||||
});
|
||||
forwardMessage(
|
||||
"serviceWorker",
|
||||
"runtime/gmApi",
|
||||
this.server,
|
||||
this.send,
|
||||
(data: { api: string; params: any }, con: GetSender) => {
|
||||
// 拦截关注的action
|
||||
console.log("拦截", data);
|
||||
// 拦截关注的api
|
||||
switch (data.api) {
|
||||
case "CAT_createBlobUrl": {
|
||||
const file = data.params[0] as File;
|
||||
|
@ -198,6 +198,53 @@ export default class GMApi {
|
||||
return (<CustomEventMessage>this.message).getAndDelRelatedTarget(data.relatedTarget);
|
||||
}
|
||||
|
||||
menuId: number | undefined;
|
||||
|
||||
menuMap: Map<number, string> | undefined;
|
||||
|
||||
@GMContext.API()
|
||||
GM_registerMenuCommand(name: string, listener: () => void, accessKey?: string): number {
|
||||
if (!this.menuMap) {
|
||||
this.menuMap = new Map();
|
||||
}
|
||||
let flag = 0;
|
||||
this.menuMap.forEach((val, key) => {
|
||||
if (val === name) {
|
||||
flag = key;
|
||||
}
|
||||
});
|
||||
if (flag) {
|
||||
return flag;
|
||||
}
|
||||
if (!this.menuId) {
|
||||
this.menuId = 1;
|
||||
} else {
|
||||
this.menuId += 1;
|
||||
}
|
||||
const id = this.menuId;
|
||||
this.connect("GM_registerMenuCommand", [id, name, accessKey]).then((con) => {
|
||||
con.onMessage((data: { action: string; data: any }) => {
|
||||
if (data.action === "onClick") {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
con.onDisconnect(() => {
|
||||
this.menuMap?.delete(id);
|
||||
});
|
||||
});
|
||||
this.menuMap.set(id, name);
|
||||
return id;
|
||||
}
|
||||
|
||||
@GMContext.API()
|
||||
GM_unregisterMenuCommand(id: number): void {
|
||||
if (!this.menuMap) {
|
||||
this.menuMap = new Map();
|
||||
}
|
||||
this.menuMap.delete(id);
|
||||
this.sendMessage("GM_unregisterMenuCommand", [id]);
|
||||
}
|
||||
|
||||
// 用于脚本跨域请求,需要@connect domain指定允许的域名
|
||||
@GMContext.API({
|
||||
depend: ["CAT_fetchBlob", "CAT_createBlobUrl", "CAT_fetchDocument"],
|
||||
@ -252,7 +299,6 @@ export default class GMApi {
|
||||
values.map(async (val) => {
|
||||
if (val instanceof File) {
|
||||
const url = await this.CAT_createBlobUrl(val);
|
||||
console.log(url);
|
||||
data.push({
|
||||
key,
|
||||
type: "file",
|
||||
|
Reference in New Issue
Block a user