mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-26 21:21:53 +08:00
add inject content ui
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import {ActionType, injectScriptAndSendMessage, WebSocketManager} from './socket.js';
|
import {ActionType, injectScriptAndSendMessage, WebSocketManager} from './socket.js';
|
||||||
import { setupProxyHandlers } from './proxy.js';
|
import { setupProxyHandlers } from './proxy.js';
|
||||||
import { ProxyActionType } from './types/action.js';
|
|
||||||
|
|
||||||
console.info("Chrome Extension Background is loaded");
|
console.info("Chrome Extension Background is loaded");
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ chrome.sidePanel.setOptions({
|
|||||||
console.error('Error setting side panel options:', error);
|
console.error('Error setting side panel options:', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
|
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||||
console.log("msg", msg)
|
console.log("msg", msg)
|
||||||
switch (msg.action) {
|
switch (msg.action) {
|
||||||
case ActionType.CONNECT:
|
case ActionType.CONNECT:
|
||||||
|
|||||||
@@ -22,6 +22,13 @@
|
|||||||
"service_worker": "background.js",
|
"service_worker": "background.js",
|
||||||
"type": "module"
|
"type": "module"
|
||||||
},
|
},
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": ["https://github.com/*"],
|
||||||
|
"run_at": "document_start",
|
||||||
|
"js": ["proxy/content.js"]
|
||||||
|
}
|
||||||
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"proxy",
|
"proxy",
|
||||||
"storage",
|
"storage",
|
||||||
@@ -42,7 +49,8 @@
|
|||||||
"types/*.js",
|
"types/*.js",
|
||||||
"proxy/*.js",
|
"proxy/*.js",
|
||||||
"socket.js",
|
"socket.js",
|
||||||
"proxy.js"
|
"proxy.js",
|
||||||
|
"proxy/content.js"
|
||||||
],
|
],
|
||||||
"matches": ["<all_urls>"]
|
"matches": ["<all_urls>"]
|
||||||
}
|
}
|
||||||
|
|||||||
+111
-50
@@ -42,6 +42,9 @@ async function handleSetProxyConfig(config, sendResponse) {
|
|||||||
|
|
||||||
console.log('Direct connection set successfully');
|
console.log('Direct connection set successfully');
|
||||||
sendResponse({success: true});
|
sendResponse({success: true});
|
||||||
|
|
||||||
|
// 通知所有 content scripts 更新
|
||||||
|
await notifyProxyStatusChanged();
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to set direct connection');
|
console.error('Failed to set direct connection');
|
||||||
sendResponse({
|
sendResponse({
|
||||||
@@ -90,6 +93,9 @@ async function handleSetProxyConfig(config, sendResponse) {
|
|||||||
|
|
||||||
console.log('System proxy set successfully');
|
console.log('System proxy set successfully');
|
||||||
sendResponse({success: true});
|
sendResponse({success: true});
|
||||||
|
|
||||||
|
// 通知所有 content scripts 更新
|
||||||
|
await notifyProxyStatusChanged();
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to set system proxy');
|
console.error('Failed to set system proxy');
|
||||||
sendResponse({
|
sendResponse({
|
||||||
@@ -155,6 +161,9 @@ async function handleSetProxyConfig(config, sendResponse) {
|
|||||||
|
|
||||||
console.log('Proxy successfully set:', settings.value);
|
console.log('Proxy successfully set:', settings.value);
|
||||||
sendResponse({success: true});
|
sendResponse({success: true});
|
||||||
|
|
||||||
|
// 通知所有 content scripts 更新
|
||||||
|
await notifyProxyStatusChanged();
|
||||||
} else {
|
} else {
|
||||||
console.error('Proxy settings verification failed');
|
console.error('Proxy settings verification failed');
|
||||||
sendResponse({
|
sendResponse({
|
||||||
@@ -173,23 +182,10 @@ async function handleSetProxyConfig(config, sendResponse) {
|
|||||||
|
|
||||||
async function handleClearProxyConfig(sendResponse) {
|
async function handleClearProxyConfig(sendResponse) {
|
||||||
try {
|
try {
|
||||||
await new Promise((resolve) => {
|
await chrome.proxy.settings.clear({
|
||||||
chrome.proxy.settings.clear({
|
scope: 'regular'
|
||||||
scope: 'regular'
|
|
||||||
}, resolve);
|
|
||||||
});
|
});
|
||||||
|
// 获取所有配置并禁用
|
||||||
await new Promise((resolve) => {
|
|
||||||
chrome.proxy.settings.set({
|
|
||||||
value: {mode: "system"},
|
|
||||||
scope: 'regular'
|
|
||||||
}, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 只移除当前代理配置,保留代理列表
|
|
||||||
await proxyStore.clearCurrentProxy();
|
|
||||||
|
|
||||||
// 更新所有代理的启用状态
|
|
||||||
const configs = await proxyStore.getProxyConfigs();
|
const configs = await proxyStore.getProxyConfigs();
|
||||||
const updatedConfigs = configs.map(config => ({
|
const updatedConfigs = configs.map(config => ({
|
||||||
...config,
|
...config,
|
||||||
@@ -197,25 +193,13 @@ async function handleClearProxyConfig(sendResponse) {
|
|||||||
}));
|
}));
|
||||||
await proxyStore.saveProxyConfigs(updatedConfigs);
|
await proxyStore.saveProxyConfigs(updatedConfigs);
|
||||||
|
|
||||||
const settings = await getProxySettings();
|
sendResponse({ success: true });
|
||||||
const isSuccess = settings.value.mode === "system";
|
|
||||||
|
|
||||||
if (isSuccess) {
|
// 通知所有 content scripts 更新
|
||||||
console.log('Proxy successfully cleared');
|
await notifyProxyStatusChanged();
|
||||||
sendResponse({success: true});
|
|
||||||
} else {
|
|
||||||
console.error('Failed to clear proxy settings');
|
|
||||||
sendResponse({
|
|
||||||
success: false,
|
|
||||||
error: '无法清除代理设置'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error clearing proxy:', error);
|
console.error('Error clearing proxy config:', error);
|
||||||
sendResponse({
|
sendResponse({ success: false, error: error.message });
|
||||||
success: false,
|
|
||||||
error: error.message || '清除代理时发生错误'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +345,9 @@ export function setupProxyHandlers() {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ProxyActionType.CLEAR_PROXY_CONFIG:
|
case ProxyActionType.CLEAR_PROXY_CONFIG:
|
||||||
handleClearProxyConfig(sendResponse);
|
(async () => {
|
||||||
|
await handleClearProxyConfig(sendResponse);
|
||||||
|
})();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ProxyActionType.GET_PROXY_STATUS:
|
case ProxyActionType.GET_PROXY_STATUS:
|
||||||
@@ -394,17 +380,15 @@ export function setupProxyHandlers() {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ProxyActionType.GET_PROXY_CONFIGS:
|
case ProxyActionType.GET_PROXY_CONFIGS:
|
||||||
proxyStore.getProxyConfigs().then(configs => {
|
(async () => {
|
||||||
sendResponse({
|
try {
|
||||||
success: true,
|
const configs = await proxyStore.getProxyConfigs();
|
||||||
data: configs
|
sendResponse({ success: true, data: configs });
|
||||||
});
|
} catch (error) {
|
||||||
}).catch(error => {
|
console.error('Error getting proxy configs:', error);
|
||||||
sendResponse({
|
sendResponse({ success: false, error: error.message });
|
||||||
success: false,
|
}
|
||||||
error: error.message
|
})();
|
||||||
});
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ProxyActionType.ADD_PROXY_CONFIG:
|
case ProxyActionType.ADD_PROXY_CONFIG:
|
||||||
@@ -422,7 +406,7 @@ export function setupProxyHandlers() {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ProxyActionType.UPDATE_PROXY_CONFIG:
|
case ProxyActionType.UPDATE_PROXY_CONFIG:
|
||||||
(async () => { // 使用立即执行的异步函数
|
(async () => {
|
||||||
try {
|
try {
|
||||||
if (!msg.configs || !Array.isArray(msg.configs)) {
|
if (!msg.configs || !Array.isArray(msg.configs)) {
|
||||||
throw new Error('无效的配置数据');
|
throw new Error('无效的配置数据');
|
||||||
@@ -440,6 +424,9 @@ export function setupProxyHandlers() {
|
|||||||
success: true,
|
success: true,
|
||||||
data: updatedConfigs
|
data: updatedConfigs
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 通知所有 content scripts 更新
|
||||||
|
await notifyProxyStatusChanged();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating proxy configs:', error);
|
console.error('Error updating proxy configs:', error);
|
||||||
sendResponse({
|
sendResponse({
|
||||||
@@ -448,7 +435,50 @@ export function setupProxyHandlers() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return true; // 保持消息端口打开
|
return true;
|
||||||
|
|
||||||
|
case 'OPEN_OPTIONS_PAGE':
|
||||||
|
// 打开选项页
|
||||||
|
chrome.tabs.create({
|
||||||
|
url: chrome.runtime.getURL('/proxy/options.html')
|
||||||
|
}).then(tab => {
|
||||||
|
if (msg.triggerAdd) {
|
||||||
|
// 如果需要触发添加代理,等待页面加载完成
|
||||||
|
const listener = (tabId, changeInfo) => {
|
||||||
|
if (tabId === tab.id && changeInfo.status === 'complete') {
|
||||||
|
chrome.tabs.onUpdated.removeListener(listener);
|
||||||
|
// 向选项页发送消息触发添加代理
|
||||||
|
chrome.tabs.sendMessage(tab.id, {
|
||||||
|
action: 'TRIGGER_ADD_PROXY'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
chrome.tabs.onUpdated.addListener(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sendResponse({ success: true });
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'PROXY_GET_STATUS':
|
||||||
|
return handleGetProxyStatus(sendResponse);
|
||||||
|
|
||||||
|
case 'PROXY_GET_CONFIGS':
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const configs = await proxyStore.getProxyConfigs();
|
||||||
|
sendResponse({ success: true, data: configs });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting proxy configs:', error);
|
||||||
|
sendResponse({ success: false, error: error.message });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'PROXY_SET_CONFIG':
|
||||||
|
return handleSetProxyConfig(msg.config, sendResponse);
|
||||||
|
|
||||||
|
case 'PROXY_CLEAR_CONFIG':
|
||||||
|
return handleClearProxyConfig(sendResponse);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -458,9 +488,13 @@ export function setupProxyHandlers() {
|
|||||||
// 确保默认配置存在
|
// 确保默认配置存在
|
||||||
await ProxySettings.setDefaultConfigs();
|
await ProxySettings.setDefaultConfigs();
|
||||||
|
|
||||||
// 清除之前的代理设置
|
// 设置为系统代理
|
||||||
await handleClearProxyConfig(() => {
|
await handleSetProxyConfig({
|
||||||
});
|
id: 'system',
|
||||||
|
name: '[系统代理]',
|
||||||
|
proxyType: 'system',
|
||||||
|
enabled: true
|
||||||
|
}, () => {});
|
||||||
|
|
||||||
// 设置认证监听
|
// 设置认证监听
|
||||||
await ProxyAuth.setupAuthListener();
|
await ProxyAuth.setupAuthListener();
|
||||||
@@ -468,4 +502,31 @@ export function setupProxyHandlers() {
|
|||||||
console.error('Error during installation:', error);
|
console.error('Error during installation:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 添加启动时的初始化
|
||||||
|
chrome.runtime.onStartup.addListener(async () => {
|
||||||
|
try {
|
||||||
|
// 设置为系统代理
|
||||||
|
await handleSetProxyConfig({
|
||||||
|
id: 'system',
|
||||||
|
name: '[系统代理]',
|
||||||
|
proxyType: 'system',
|
||||||
|
enabled: true
|
||||||
|
}, () => {});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during startup:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当代理状态改变时通知所有内容脚本
|
||||||
|
async function notifyProxyStatusChanged() {
|
||||||
|
const tabs = await chrome.tabs.query({});
|
||||||
|
for (const tab of tabs) {
|
||||||
|
try {
|
||||||
|
chrome.tabs.sendMessage(tab.id, { action: 'PROXY_STATUS_CHANGED' });
|
||||||
|
} catch (error) {
|
||||||
|
// 忽略不支持的标签页
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,489 @@
|
|||||||
|
console.log("Content script starting...");
|
||||||
|
|
||||||
|
// 代理操作类型常量
|
||||||
|
const ProxyActionType = {
|
||||||
|
SET_PROXY_CONFIG: 'SET_PROXY_CONFIG',
|
||||||
|
CLEAR_PROXY_CONFIG: 'CLEAR_PROXY_CONFIG',
|
||||||
|
GET_PROXY_STATUS: 'GET_PROXY_STATUS',
|
||||||
|
GET_PROXY_CONFIGS: 'GET_PROXY_CONFIGS',
|
||||||
|
UPDATE_PROXY_CONFIG: 'UPDATE_PROXY_CONFIG'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加一个通用的消息发送函数
|
||||||
|
async function sendMessageWithRetry(message, maxRetries = 3) {
|
||||||
|
for (let i = 0; i < maxRetries; i++) {
|
||||||
|
try {
|
||||||
|
const response = await chrome.runtime.sendMessage(message);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Attempt ${i + 1} failed:`, error);
|
||||||
|
if (i === maxRetries - 1) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
// 等待一小段时间后重试
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前代理状态
|
||||||
|
async function getCurrentProxy() {
|
||||||
|
try {
|
||||||
|
const response = await sendMessageWithRetry({
|
||||||
|
action: ProxyActionType.GET_PROXY_STATUS
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
console.log('No response from background script');
|
||||||
|
return { enable: false, proxy: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查响应格式
|
||||||
|
if (!response.success) {
|
||||||
|
console.error('Error in proxy status response:', response.error);
|
||||||
|
return { enable: false, proxy: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = response.data;
|
||||||
|
console.log('Proxy status from background:', status);
|
||||||
|
|
||||||
|
// 根据状态返回正确的格式
|
||||||
|
if (status.mode === 'fixed_servers' && status.enabled && status.config) {
|
||||||
|
const config = status.config;
|
||||||
|
// 只在确实有配置时才返回代理信息
|
||||||
|
if (config.scheme && config.host && config.port) {
|
||||||
|
return {
|
||||||
|
enable: true,
|
||||||
|
proxy: `${config.scheme}://${config.host}:${config.port}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于直连或系统代理,返回相应状态
|
||||||
|
return {
|
||||||
|
enable: false,
|
||||||
|
proxy: status.mode === 'system' ? 'system' : ''
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting proxy status:', error);
|
||||||
|
return { enable: false, proxy: '' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有代理配置
|
||||||
|
async function getProxyConfigs() {
|
||||||
|
try {
|
||||||
|
const response = await sendMessageWithRetry({
|
||||||
|
action: ProxyActionType.GET_PROXY_CONFIGS
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
console.log('No response from background script');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (!response.success) {
|
||||||
|
console.error('Error in response:', response.error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return response.data || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting proxy configs:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换代理
|
||||||
|
async function switchProxy(config) {
|
||||||
|
try {
|
||||||
|
console.log('Switching proxy:', config);
|
||||||
|
await sendMessageWithRetry({
|
||||||
|
action: ProxyActionType.SET_PROXY_CONFIG,
|
||||||
|
config: config
|
||||||
|
});
|
||||||
|
|
||||||
|
await updatePanel();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error switching proxy:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除代理
|
||||||
|
async function clearProxy() {
|
||||||
|
try {
|
||||||
|
const response = await sendMessageWithRetry({
|
||||||
|
action: ProxyActionType.SET_PROXY_CONFIG,
|
||||||
|
config: {
|
||||||
|
id: 'direct',
|
||||||
|
name: '[直接连接]',
|
||||||
|
proxyType: 'direct',
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Clear proxy response:', response);
|
||||||
|
await updatePanel();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error clearing proxy:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新面板显示
|
||||||
|
async function updatePanel() {
|
||||||
|
const panel = document.getElementById('yakit-proxy-panel')?.shadowRoot?.querySelector('.panel-content');
|
||||||
|
if (!panel) return;
|
||||||
|
|
||||||
|
const currentProxy = await getCurrentProxy();
|
||||||
|
const configs = await getProxyConfigs();
|
||||||
|
|
||||||
|
console.log('Current proxy status:', currentProxy);
|
||||||
|
|
||||||
|
// 修改这里的判断逻辑
|
||||||
|
let html = `
|
||||||
|
<div class="proxy-item ${currentProxy.proxy === '' ? 'active' : ''}" data-id="direct">
|
||||||
|
<span style="color: ${currentProxy.proxy === '' ? '#ff6b00' : '#666'}">🔴</span>
|
||||||
|
<span>[直接连接]</span>
|
||||||
|
</div>
|
||||||
|
<div class="proxy-item ${currentProxy.proxy === 'system' ? 'active' : ''}" data-id="system">
|
||||||
|
<span style="color: ${currentProxy.proxy === 'system' ? '#ff6b00' : '#666'}">⚙️</span>
|
||||||
|
<span>[系统代理]</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 添加自定义代理配置
|
||||||
|
configs.forEach(config => {
|
||||||
|
if (config.id !== 'direct' && config.id !== 'system') {
|
||||||
|
// 检查当前代理是否与配置匹配
|
||||||
|
const isActive = currentProxy.enable &&
|
||||||
|
currentProxy.proxy === `${config.scheme}://${config.host}:${config.port}`;
|
||||||
|
html += `
|
||||||
|
<div class="proxy-item ${isActive ? 'active' : ''}" data-id="${config.id}">
|
||||||
|
<span style="color: ${isActive ? '#ff6b00' : '#666'}">🌐</span>
|
||||||
|
<span>${config.name}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 修改添加操作按钮部分
|
||||||
|
html += `
|
||||||
|
<div class="add-proxy">
|
||||||
|
<span>➕</span>
|
||||||
|
<span>添加代理...</span>
|
||||||
|
</div>
|
||||||
|
<div class="settings">
|
||||||
|
<span>👨💻</span>
|
||||||
|
<span>选项</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
panel.innerHTML = html;
|
||||||
|
|
||||||
|
// 添加事件监听
|
||||||
|
panel.querySelectorAll('.proxy-item').forEach(item => {
|
||||||
|
item.addEventListener('click', async () => {
|
||||||
|
const id = item.dataset.id;
|
||||||
|
if (id === 'direct') {
|
||||||
|
await clearProxy();
|
||||||
|
} else if (id === 'system') {
|
||||||
|
await switchProxy({
|
||||||
|
id: 'system',
|
||||||
|
name: '[系统代理]',
|
||||||
|
proxyType: 'system'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const config = configs.find(c => c.id === id);
|
||||||
|
if (config) {
|
||||||
|
await switchProxy(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 修改添加代理和选项按钮的事件处理
|
||||||
|
panel.querySelector('.add-proxy')?.addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
// 通过发送消息给 background script 来处理添加代理
|
||||||
|
await sendMessageWithRetry({
|
||||||
|
action: 'OPEN_OPTIONS_PAGE',
|
||||||
|
triggerAdd: true // 标记需要触发添加代理
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error handling add proxy:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
panel.querySelector('.settings')?.addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
// 通过发送消息给 background script 来打开选项页
|
||||||
|
await sendMessageWithRetry({
|
||||||
|
action: 'OPEN_OPTIONS_PAGE'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error opening options page:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建并注入悬浮框
|
||||||
|
function createFloatingPanel() {
|
||||||
|
console.log("Creating floating panel...");
|
||||||
|
|
||||||
|
// 检查是否已存在面板
|
||||||
|
if (document.getElementById('yakit-proxy-panel')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建容器
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.id = 'yakit-proxy-panel';
|
||||||
|
|
||||||
|
// 创建 shadow DOM
|
||||||
|
const shadow = container.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
|
// 添加样式
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
.floating-panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 0;
|
||||||
|
width: 200px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px 0 0 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
z-index: 2147483647;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-panel.collapsed {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
padding: 4px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
border-radius: 8px 0 0 0;
|
||||||
|
background: #f8f9fa;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-trigger {
|
||||||
|
position: absolute;
|
||||||
|
left: -20px;
|
||||||
|
top: 0;
|
||||||
|
width: 20px;
|
||||||
|
height: 100%;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 8px 0 0 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: -2px 0 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-trigger:hover {
|
||||||
|
background: #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-trigger::after {
|
||||||
|
content: '◀';
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-panel.collapsed .collapse-trigger::after {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
color: #666;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item.active {
|
||||||
|
color: #ff6b00 !important;
|
||||||
|
background: #fff7e6;
|
||||||
|
border-left: 3px solid #ff6b00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item.active span:first-child {
|
||||||
|
color: #ff6b00 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item span:first-child {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-item:hover span:first-child {
|
||||||
|
color: #ff6b00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-proxy {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: #1890ff;
|
||||||
|
cursor: pointer;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-proxy:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 创建面板内容
|
||||||
|
const panel = document.createElement('div');
|
||||||
|
panel.className = 'floating-panel';
|
||||||
|
panel.innerHTML = `
|
||||||
|
<div class="collapse-trigger"></div>
|
||||||
|
<div class="panel-header">
|
||||||
|
<span>代理设置</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content">
|
||||||
|
<div class="proxy-item active">
|
||||||
|
<span>🔴</span>
|
||||||
|
<span>[直接连接]</span>
|
||||||
|
</div>
|
||||||
|
<div class="proxy-item">
|
||||||
|
<span>⚙️</span>
|
||||||
|
<span>[系统代理]</span>
|
||||||
|
</div>
|
||||||
|
<div class="add-proxy">
|
||||||
|
<span>➕</span>
|
||||||
|
<span>添加代理...</span>
|
||||||
|
</div>
|
||||||
|
<div class="settings">
|
||||||
|
<span>👨💻</span>
|
||||||
|
<span>选项</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 将样式和面板添加到 shadow DOM
|
||||||
|
shadow.appendChild(style);
|
||||||
|
shadow.appendChild(panel);
|
||||||
|
|
||||||
|
// 将容器添加到页面
|
||||||
|
document.body.appendChild(container);
|
||||||
|
|
||||||
|
// 添加事件监听器
|
||||||
|
const addEventListeners = () => {
|
||||||
|
// 收起/展开功能
|
||||||
|
panel.querySelector('.collapse-trigger')?.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
panel.classList.toggle('collapsed');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加代理按钮
|
||||||
|
panel.querySelector('.add-proxy')?.addEventListener('click', () => {
|
||||||
|
chrome.runtime.sendMessage({ action: 'OPEN_OPTIONS_PAGE' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置按钮
|
||||||
|
panel.querySelector('.settings')?.addEventListener('click', () => {
|
||||||
|
chrome.runtime.sendMessage({ action: 'OPEN_OPTIONS_PAGE' });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化事件监听器
|
||||||
|
addEventListeners();
|
||||||
|
|
||||||
|
// 初始更新面板
|
||||||
|
updatePanel();
|
||||||
|
|
||||||
|
// 添加代理变化监听
|
||||||
|
let messageListener = (message) => {
|
||||||
|
if (message.action === 'PROXY_STATUS_CHANGED') {
|
||||||
|
updatePanel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确保只添加一次监听器
|
||||||
|
chrome.runtime.onMessage.removeListener(messageListener);
|
||||||
|
chrome.runtime.onMessage.addListener(messageListener);
|
||||||
|
|
||||||
|
// 验证面板是否成功创建
|
||||||
|
console.log("Panel created:", {
|
||||||
|
containerExists: !!document.getElementById('yakit-proxy-panel'),
|
||||||
|
containerVisible: window.getComputedStyle(container).display !== 'none',
|
||||||
|
shadowRoot: !!container.shadowRoot,
|
||||||
|
panelElement: !!container.shadowRoot?.querySelector('.floating-panel')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 MutationObserver 确保在 DOM 准备好时创建面板
|
||||||
|
function initPanel() {
|
||||||
|
if (document.body) {
|
||||||
|
console.log("Body found, creating panel");
|
||||||
|
// 确保background script已经准备好
|
||||||
|
sendMessageWithRetry({ action: 'PING' })
|
||||||
|
.then(() => {
|
||||||
|
createFloatingPanel();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Failed to initialize panel:', error);
|
||||||
|
// 可以在这里添加重试逻辑
|
||||||
|
setTimeout(initPanel, 1000);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("Body not found, waiting...");
|
||||||
|
const observer = new MutationObserver((mutations, obs) => {
|
||||||
|
if (document.body) {
|
||||||
|
console.log("Body found via observer");
|
||||||
|
obs.disconnect();
|
||||||
|
initPanel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.documentElement, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试多种方式来确保面板被创建
|
||||||
|
console.log("Setting up initialization...");
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
console.log("Window load triggered");
|
||||||
|
initPanel();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 在关键位置添加更多日志
|
||||||
|
console.log("Document readyState:", document.readyState);
|
||||||
|
console.log("Document body exists:", !!document.body);
|
||||||
|
console.log("Document documentElement exists:", !!document.documentElement);
|
||||||
@@ -178,3 +178,26 @@ body {
|
|||||||
.menu-item-add:hover .anticon {
|
.menu-item-add:hover .anticon {
|
||||||
color: var(--yakit-primary);
|
color: var(--yakit-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-loading {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-loading {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-selected {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background-color: var(--yakit-primary-5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加过渡效果 */
|
||||||
|
.ant-menu-item {
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu-item .menu-icon {
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
@@ -55,6 +55,7 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [currentMode, setCurrentMode] = useState<string>('direct');
|
const [currentMode, setCurrentMode] = useState<string>('direct');
|
||||||
const [customProxies, setCustomProxies] = useState<CustomProxy[]>([]);
|
const [customProxies, setCustomProxies] = useState<CustomProxy[]>([]);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadProxyStatus();
|
loadProxyStatus();
|
||||||
@@ -110,6 +111,7 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
|
|
||||||
const handleApplyConfig = async (mode: string) => {
|
const handleApplyConfig = async (mode: string) => {
|
||||||
try {
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
const fixedMode = FIXED_MODES.find(fixed => fixed.key === mode);
|
const fixedMode = FIXED_MODES.find(fixed => fixed.key === mode);
|
||||||
const customProxy = customProxies.find(proxy => proxy.key === mode);
|
const customProxy = customProxies.find(proxy => proxy.key === mode);
|
||||||
|
|
||||||
@@ -120,17 +122,30 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setCurrentMode(mode);
|
||||||
|
|
||||||
|
if (customProxy) {
|
||||||
|
setCustomProxies(prev => prev.map(p => ({
|
||||||
|
...p,
|
||||||
|
enabled: p.key === mode
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
const response = await chrome.runtime.sendMessage({
|
const response = await chrome.runtime.sendMessage({
|
||||||
action: ProxyActionType.SET_PROXY_CONFIG,
|
action: ProxyActionType.SET_PROXY_CONFIG,
|
||||||
config
|
config
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.success) {
|
if (response?.success === false) {
|
||||||
setCurrentMode(mode);
|
throw new Error(response.error || '设置代理失败');
|
||||||
await loadCustomProxies();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await loadCustomProxies();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to apply proxy config:', error);
|
console.error('Error applying proxy config:', error);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,12 +179,9 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
const listener = (tabId: number, changeInfo: chrome.tabs.TabChangeInfo) => {
|
const listener = (tabId: number, changeInfo: chrome.tabs.TabChangeInfo) => {
|
||||||
if (tabId === tab.id && changeInfo.status === 'complete') {
|
if (tabId === tab.id && changeInfo.status === 'complete') {
|
||||||
chrome.tabs.onUpdated.removeListener(listener);
|
chrome.tabs.onUpdated.removeListener(listener);
|
||||||
// 给页面一点时间完全初始化
|
|
||||||
// setTimeout(() => {
|
|
||||||
chrome.tabs.sendMessage(tab.id!, {
|
chrome.tabs.sendMessage(tab.id!, {
|
||||||
action: 'TRIGGER_ADD_PROXY'
|
action: 'TRIGGER_ADD_PROXY'
|
||||||
});
|
});
|
||||||
// }, 500); // 减少延迟时间
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,14 +205,17 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
key: mode.key,
|
key: mode.key,
|
||||||
icon: <span className="menu-icon" style={{ color: mode.color }}>{mode.icon}</span>,
|
icon: <span className="menu-icon" style={{ color: mode.color }}>{mode.icon}</span>,
|
||||||
label: mode.name,
|
label: mode.name,
|
||||||
className: currentMode === mode.key ? 'menu-item-selected' : ''
|
className: `${currentMode === mode.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`
|
||||||
})),
|
})),
|
||||||
{ type: 'divider' },
|
{ type: 'divider' },
|
||||||
...customProxies.map(proxy => ({
|
...customProxies.map(proxy => ({
|
||||||
key: proxy.key,
|
key: proxy.key,
|
||||||
icon: <span className="menu-icon" style={{ color: proxy.color }}><GlobalOutlined /></span>,
|
icon: <span className="menu-icon" style={{ color: proxy.color }}><GlobalOutlined /></span>,
|
||||||
label: <span style={{ color: proxy.enabled ? 'var(--yakit-primary)' : 'inherit' }}>{proxy.name}</span>,
|
label: <span style={{
|
||||||
className: proxy.enabled ? 'menu-item-selected' : ''
|
color: currentMode === proxy.key ? 'var(--yakit-primary)' : 'inherit',
|
||||||
|
opacity: isLoading ? 0.7 : 1
|
||||||
|
}}>{proxy.name}</span>,
|
||||||
|
className: `${currentMode === proxy.key ? 'menu-item-selected' : ''} ${isLoading ? 'menu-item-loading' : ''}`
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
key: 'add',
|
key: 'add',
|
||||||
@@ -220,8 +235,9 @@ export const ProxySwitch: React.FC<ProxySwitchProps> = ({
|
|||||||
<Menu
|
<Menu
|
||||||
items={menuItems}
|
items={menuItems}
|
||||||
selectedKeys={[currentMode]}
|
selectedKeys={[currentMode]}
|
||||||
onClick={({ key }) => handleModeChange(key)}
|
onClick={({ key }) => !isLoading && handleModeChange(key)}
|
||||||
style={{ width: 180 }}
|
style={{ width: 180 }}
|
||||||
|
className={isLoading ? 'menu-loading' : ''}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user