新增備份、恢復、右鍵替換詞語功能
This commit is contained in:
parent
db0a715fc8
commit
dc6c364f29
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
12
readme.md
12
readme.md
|
|
@ -1,2 +1,14 @@
|
||||||
# 支語寶
|
# 支語寶
|
||||||
將所有網頁中的指定詞語替換為其他詞語
|
將所有網頁中的指定詞語替換為其他詞語
|
||||||
|
|
||||||
|
## 設定畫面
|
||||||
|
提供新增刪除,以及匯出匯入功能
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
1. 可進入設定畫面新增詞彙
|
||||||
|

|
||||||
|
2. 反白想替換的文字,並選擇「替換詞語」
|
||||||
|

|
||||||
|
|
||||||
|
## 其他
|
||||||
|
所有程式碼皆為Chatgpt撰寫,並手動修改部分用詞
|
||||||
|
|
@ -9,3 +9,38 @@ chrome.runtime.onInstalled.addListener(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// 創建右鍵選單
|
||||||
|
chrome.runtime.onInstalled.addListener(() => {
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
id: "replaceWord",
|
||||||
|
title: "替換詞語",
|
||||||
|
contexts: ["selection"] // 僅在選取文字時顯示
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 處理選單點擊事件
|
||||||
|
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||||
|
if (info.menuItemId === "replaceWord" && info.selectionText) {
|
||||||
|
const selectedText = info.selectionText;
|
||||||
|
// 提示用戶輸入替換詞語
|
||||||
|
chrome.scripting.executeScript({
|
||||||
|
target: { tabId: tab.id },
|
||||||
|
func: (selectedText) => {
|
||||||
|
const newWord = prompt(`將「${selectedText}」替換為:`, "");
|
||||||
|
return { selectedText, newWord };
|
||||||
|
},
|
||||||
|
args: [selectedText]
|
||||||
|
}, (results) => {
|
||||||
|
const { selectedText, newWord } = results[0].result;
|
||||||
|
if (newWord && newWord !== selectedText) {
|
||||||
|
// 儲存到 replacements 中
|
||||||
|
chrome.storage.local.get("replacements", (data) => {
|
||||||
|
const replacements = data.replacements || {};
|
||||||
|
replacements[selectedText] = newWord;
|
||||||
|
chrome.storage.local.set({ replacements });
|
||||||
|
alert(`已將「${selectedText}」替換為「${newWord}」`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -10,10 +10,10 @@ function replaceText(node, replacements) {
|
||||||
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
node.childNodes.forEach((child) => replaceText(child, replacements));
|
node.childNodes.forEach((child) => replaceText(child, replacements));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化替換
|
// 初始化替換
|
||||||
function initializeReplacements() {
|
function initializeReplacements() {
|
||||||
chrome.storage.local.get("replacements", (data) => {
|
chrome.storage.local.get("replacements", (data) => {
|
||||||
const replacements = data.replacements || {};
|
const replacements = data.replacements || {};
|
||||||
replaceText(document.body, replacements);
|
replaceText(document.body, replacements);
|
||||||
|
|
@ -30,6 +30,13 @@ function replaceText(node, replacements) {
|
||||||
});
|
});
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 監聽 storage 更新,動態更新替換內容
|
||||||
|
chrome.storage.onChanged.addListener((changes) => {
|
||||||
|
if (changes.replacements) {
|
||||||
initializeReplacements();
|
initializeReplacements();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initializeReplacements();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "支語寶",
|
"name": "支語寶",
|
||||||
"version": "0.1.0 alpha",
|
"version": "0.1.0",
|
||||||
"description": "將所有網頁中的指定詞語替換為其他詞語。",
|
"description": "將所有網頁中的指定詞語替換為其他詞語。",
|
||||||
"permissions": ["storage", "activeTab", "scripting"],
|
"permissions": ["storage", "activeTab", "scripting", "contextMenus"],
|
||||||
"host_permissions": ["<all_urls>"],
|
"host_permissions": ["<all_urls>"],
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "background.js"
|
"service_worker": "background.js"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<title>支語寶</title>
|
<title>支語寶</title>
|
||||||
<style>
|
<style>
|
||||||
body { font-family: Arial, sans-serif; padding: 20px; }
|
body { font-family: Arial, sans-serif; padding: 20px; }
|
||||||
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
table { width: 600px; border-collapse: collapse; margin-bottom: 20px; }
|
||||||
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||||
th { background-color: #f4f4f4; }
|
th { background-color: #f4f4f4; }
|
||||||
button { margin-right: 10px; }
|
button { margin-right: 10px; }
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>支語寶</h1>
|
<h1>支語寶</h1>
|
||||||
|
<h2>設定詞語</h2>
|
||||||
<table id="replacementsTable">
|
<table id="replacementsTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -27,6 +28,11 @@
|
||||||
<input type="text" id="original" placeholder="原始詞語">
|
<input type="text" id="original" placeholder="原始詞語">
|
||||||
<input type="text" id="replacement" placeholder="替換詞語">
|
<input type="text" id="replacement" placeholder="替換詞語">
|
||||||
<button id="addButton">新增</button>
|
<button id="addButton">新增</button>
|
||||||
|
<br /><br />
|
||||||
|
<h2>備份/恢復</h2>
|
||||||
|
<button id="exportButton">匯出</button>
|
||||||
|
<input type="file" id="importFile" style="display: none;" />
|
||||||
|
<button id="importButton">匯入</button>
|
||||||
|
|
||||||
<script src="options.js"></script>
|
<script src="options.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
const originalInput = document.getElementById("original");
|
const originalInput = document.getElementById("original");
|
||||||
const replacementInput = document.getElementById("replacement");
|
const replacementInput = document.getElementById("replacement");
|
||||||
const addButton = document.getElementById("addButton");
|
const addButton = document.getElementById("addButton");
|
||||||
|
const exportButton = document.getElementById("exportButton");
|
||||||
|
const importButton = document.getElementById("importButton");
|
||||||
|
const importFileInput = document.getElementById("importFile");
|
||||||
|
|
||||||
// 載入詞語對
|
// 載入詞語對
|
||||||
function loadReplacements() {
|
function loadReplacements() {
|
||||||
|
|
@ -54,5 +57,49 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadReplacements();
|
// 匯出詞語對
|
||||||
|
exportButton.addEventListener("click", () => {
|
||||||
|
chrome.storage.local.get("replacements", (data) => {
|
||||||
|
const replacements = data.replacements || {};
|
||||||
|
const blob = new Blob([JSON.stringify(replacements, null, 2)], { type: "application/json" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = "replacements.json";
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 匯入詞語對
|
||||||
|
importButton.addEventListener("click", () => {
|
||||||
|
importFileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
importFileInput.addEventListener("change", (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
try {
|
||||||
|
const importedReplacements = JSON.parse(e.target.result);
|
||||||
|
if (typeof importedReplacements !== "object") throw new Error();
|
||||||
|
|
||||||
|
chrome.storage.local.get("replacements", (data) => {
|
||||||
|
const currentReplacements = data.replacements || {};
|
||||||
|
const mergedReplacements = { ...currentReplacements, ...importedReplacements };
|
||||||
|
chrome.storage.local.set({ replacements: mergedReplacements }, loadReplacements);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
alert("匯入失敗,請確保檔案格式正確!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(file);
|
||||||
|
importFileInput.value = ""; // 重置 input,允許重複上傳同一檔案
|
||||||
|
});
|
||||||
|
|
||||||
|
loadReplacements();
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue