Skip to content

Commit 9bbb0a9

Browse files
committed
Toolbox
1 parent b12ff1a commit 9bbb0a9

24 files changed

+744
-526
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The Chrmoe plug-in for [Leetcode Editor](https://github.com/shuzijun/leetcode-ed
77

88
## Installation
99

10-
1. Install from the Chrome Store
10+
1. Install from the Chrome Store [link](https://chrome.google.com/webstore/detail/leetcode-editor-extension/kikcppmgphhkffcdhldclbidggbieegc)
1111
2. Download the file to install
1212

1313
## How to use

README_ZH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
## 安装方式
99

10-
1. 从Chrome商店安装
10+
1. 从Chrome商店安装 [链接](https://chrome.google.com/webstore/detail/leetcode-editor-extension/kikcppmgphhkffcdhldclbidggbieegc)
1111
2. 下载文件进行安装
1212

1313
## 使用方式

assets/icon.png

-13.3 KB
Loading

assets/pluginIcon.svg

Lines changed: 11 additions & 0 deletions
Loading

index.d.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,28 @@ declare namespace NodeJS {
66

77
interface Window {
88
dataLayer: Array
9-
gtag: (a: string, b: any, c?: any) => void
9+
gtag: (a: string, b: any, c?: any) => void
10+
}
11+
12+
interface Question {
13+
title:string
14+
slug:string
15+
}
16+
17+
interface ReplayMessage {
18+
type:string
19+
url:string
20+
body:string
21+
requestId:string
22+
tabId:number
23+
retry?:number
24+
matching?(details: chrome.webRequest.WebRequestBodyDetails,body:string): ReplayMessage
25+
dispose?(callback: Function)
26+
}
27+
28+
interface ReplayFetch{
29+
type:string
30+
method:string
31+
headers:HeadersInit
32+
dispose(callback: Function)
1033
}

locales/en/messages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@
2222
"open_ide": {
2323
"message": "Open IDE",
2424
"description": "message."
25+
},
26+
"affix_toolbox": {
27+
"message": "Toolbox",
28+
"description": "message."
2529
}
2630
}

locales/zh/messages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@
2222
"open_ide": {
2323
"message": "打开IDE",
2424
"description": "message."
25+
},
26+
"affix_toolbox": {
27+
"message": "工具箱",
28+
"description": "message."
2529
}
2630
}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "leetcode-editor-extension",
33
"displayName": "Leetcode editor extension",
4-
"version": "0.0.2",
4+
"version": "0.0.3",
55
"description": "Quickly open problems in IntelliJ Platform IDEs.",
66
"author": "shuzijun",
77
"scripts": {
@@ -36,7 +36,8 @@
3636
"https://codetop.cc/*"
3737
],
3838
"permissions": [
39-
"cookies"
39+
"cookies",
40+
"webRequest"
4041
]
4142
}
4243
}

src/background.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import CryptoJS from 'crypto-js'
2+
import {matchingType} from "~network";
3+
24
console.log("HELLO WORLD")
35

46
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
@@ -13,3 +15,31 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
1315
}
1416
return true
1517
});
18+
19+
20+
let filter:chrome.webRequest.RequestFilter = { urls: ['https://leetcode.cn/*','https://leetcode.com/*'],types: ["xmlhttprequest"] }
21+
let extraInfoSpec = ['requestBody','extraHeaders']
22+
23+
chrome.webRequest.onBeforeRequest.addListener(function(details){
24+
let postedString = ""
25+
if (details.method === "POST"){
26+
postedString = decodeURIComponent(String.fromCharCode.apply(null, new Uint8Array(details.requestBody.raw[0].bytes)))
27+
}
28+
console.log(details)
29+
let message = matchingType(details,postedString)
30+
if (message){
31+
sendTabMessage(message)
32+
}
33+
}, filter, extraInfoSpec)
34+
35+
function sendTabMessage(message) {
36+
if (message.retry>6){
37+
return
38+
}
39+
chrome.tabs.sendMessage(message.tabId,message,function(res) {
40+
if(!(res && res.status)) {
41+
message.retry = message.retry + 1
42+
setTimeout(sendTabMessage, 3000,message);
43+
}
44+
})
45+
}

src/contents/codetop-cc-list.tsx

Lines changed: 40 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,45 @@
1-
import type {PlasmoContentScript} from "plasmo"
2-
import {useStorage} from "@plasmohq/storage/hook"
3-
import React from "react"
4-
import {createRoot} from "react-dom/client"
1+
import type { PlasmoContentScript } from "plasmo";
2+
import { useStorage } from "@plasmohq/storage/hook";
3+
import React from "react";
4+
import { createRoot } from "react-dom/client";
55

6-
import {Button} from 'antd';
7-
import {GetLogoSize} from "~logo"
6+
import { Button } from "antd";
7+
import { BaseUrl, Logo } from "~tools";
88

99
export const config: PlasmoContentScript = {
10-
matches: ["https://codetop.cc/home*"]
11-
}
10+
matches: ["https://codetop.cc/home*"]
11+
};
1212

1313
export const getRootContainer = () =>
14-
new Promise((resolve) => {
15-
const checkInterval = setInterval(() => {
16-
const rootContainer = document.querySelector(".el-table__body-wrapper > .el-table__body > tbody")
17-
if (rootContainer) {
18-
clearInterval(checkInterval)
19-
resolve(rootContainer)
20-
}
21-
}, 137)
22-
})
23-
24-
const CodeTopCCList = ({sulg}) => {
25-
26-
const [showIcon] = useStorage("ShowIcon", true)
27-
const logo = GetLogoSize(14)
28-
const url = GetUrl() + sulg
29-
30-
return (<Button hidden={!showIcon} type="text" href={url} icon={logo} target='_blank'/>)
31-
}
32-
33-
export const render = async ({createRootContainer}) => {
34-
35-
const rootContainer = await createRootContainer()
36-
37-
const els = rootContainer.querySelectorAll("tr > td:nth-child(1) > div")
38-
for (let i = 0; i < els.length; i++) {
39-
const d = document.createElement("div")
40-
d.style = "display: inline;padding-right:10px"
41-
els[i].insertBefore(d, els[i].lastChild)
42-
const root = createRoot(d)
43-
let sulg = els[i].getElementsByTagName("a")[0].getAttribute("href").split('/')[4]
44-
root.render(<CodeTopCCList sulg={sulg}/>);
45-
}
46-
}
47-
48-
49-
const GetUrl = () => {
50-
const [editor] = useStorage("Editor", "leetcode-editor-pro")
51-
const [product] = useStorage("Product", "idea")
52-
const [project] = useStorage("Project", "")
53-
54-
return "jetbrains://" + product + "/" + editor + "/open?project=" + project + "&slug="
55-
}
56-
57-
export default CodeTopCCList
14+
new Promise((resolve) => {
15+
const checkInterval = setInterval(() => {
16+
const rootContainer = document.querySelector(".el-table__body-wrapper > .el-table__body > tbody");
17+
if (rootContainer) {
18+
clearInterval(checkInterval);
19+
resolve(rootContainer);
20+
}
21+
}, 137);
22+
});
23+
24+
const CodeTopCCList = ({ slug }) => {
25+
const [showIcon] = useStorage("ShowIcon", true);
26+
const logo = Logo(14);
27+
const url = BaseUrl("slug") + slug;
28+
29+
return (<Button hidden={!showIcon} type="text" href={url} icon={logo} target="_blank" />);
30+
};
31+
32+
export const render = async ({ createRootContainer }) => {
33+
const rootContainer = await createRootContainer();
34+
const els = rootContainer.querySelectorAll("tr > td:nth-child(1) > div");
35+
for (let i = 0; i < els.length; i++) {
36+
let d = document.createElement("div");
37+
d.setAttribute("style", "display: inline;padding-right:10px");
38+
els[i].insertBefore(d, els[i].lastChild);
39+
const root = createRoot(d);
40+
let slug = els[i].getElementsByTagName("a")[0].getAttribute("href").split("/")[4];
41+
root.render(<CodeTopCCList slug={slug} />);
42+
}
43+
};
44+
45+
export default CodeTopCCList;

src/contents/leetcode-affix.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import type { PlasmoContentScript, PlasmoGetInlineAnchor } from "plasmo";
2+
import { Affix, Button, Drawer, List } from "antd";
3+
import { BaseUrl, Icon as logoIcon, Style } from "~tools";
4+
import Icon from "@ant-design/icons";
5+
import React, { useEffect, useState } from "react";
6+
import {matchingDispose} from "~network";
7+
8+
export const config: PlasmoContentScript = {
9+
matches: ["https://leetcode.cn/*", "https://leetcode.com/*"],
10+
run_at: "document_end"
11+
};
12+
13+
export const getStyle = () => {
14+
const style = Style(true);
15+
const myStyle = "#plasmo-shadow-container {position: absolute !important; top: 0px; right: 0px;}";
16+
style.textContent = style.textContent + myStyle;
17+
return style;
18+
};
19+
20+
// Use this to optimize unmount lookups
21+
export const getShadowHostId = () => "leetcode-editor-affix-id";
22+
23+
export const getInlineAnchor: PlasmoGetInlineAnchor = () =>
24+
document.querySelector("body");
25+
26+
27+
const LeetcodeAffix = () => {
28+
const [questions, setQuestions] = useState<Question[]>([]);
29+
30+
const addData = (item:Question[]) => {
31+
setQuestions([...questions, ...item]);
32+
};
33+
34+
useEffect(() => {
35+
const cache = [];
36+
chrome.runtime.onMessage.addListener((message:ReplayMessage, sender, sendResponse) => {
37+
if (cache.some((value) => value === message.requestId)) {
38+
sendResponse({ status: "ok" });
39+
return true;
40+
}
41+
cache.push(message.requestId);
42+
console.log(cache);
43+
matchingDispose(message).dispose((questions:Question[]) => {addData(questions)});
44+
sendResponse({ status: "ok" });
45+
return true;
46+
});
47+
}, []);
48+
49+
50+
const [open, setOpen] = useState(false);
51+
const showDrawer = () => {
52+
let container = getContainer();
53+
container.style.height = "300px";
54+
container.style.width = "150px";
55+
setOpen(true);
56+
};
57+
const onClose = () => {
58+
setOpen(false);
59+
setTimeout(() => {
60+
let container = getContainer();
61+
container.style.height = "0px";
62+
container.style.width = "0px";
63+
}, 1000);
64+
65+
};
66+
const getContainer = (): HTMLElement => {
67+
return document.querySelector("#" + getShadowHostId()).shadowRoot.querySelector("#plasmo-shadow-container").querySelector("#containerAffix");
68+
};
69+
70+
const url = BaseUrl("slug");
71+
72+
return (
73+
<>
74+
<Affix style={{ position: "absolute", top: 80, right: 0 }}>
75+
<Button type="link" style={{ width: 40, height: 40 }} onClick={showDrawer} hidden={open}
76+
icon={<Icon component={logoIcon} />} />
77+
78+
</Affix>
79+
<Affix style={{ position: "absolute", top: 0, right: 0 }}>
80+
<div id="containerAffix"></div>
81+
</Affix>
82+
<Drawer title={ chrome.i18n.getMessage("affix_toolbox") } placement="right" destroyOnClose={true} onClose={onClose} open={open} width={150} height={200}
83+
getContainer={getContainer()}
84+
style={{ position: "absolute" }}>
85+
<List
86+
header={<div>Problem Set</div>}
87+
itemLayout="horizontal"
88+
dataSource={questions}
89+
renderItem={item => (
90+
<List.Item>
91+
<List.Item.Meta title={<a href={url + item.slug} target="_blank">{item.title}</a>} />
92+
</List.Item>
93+
)}
94+
/>
95+
</Drawer>
96+
</>
97+
);
98+
};
99+
100+
export default LeetcodeAffix;

0 commit comments

Comments
 (0)