80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/service_worker.js:
--------------------------------------------------------------------------------
1 | function initSettings() {
2 | chrome.storage.local.set({
3 | toggle: true,
4 | ttsToggle: true,
5 | ttsVoices: {
6 | lang: "en",
7 | },
8 | highlightBackground: "#FFFF0010",
9 | highlightText: "",
10 | bubbleBackground: "#FFE4C4",
11 | bubbleText: "",
12 | syncTime: 0,
13 | //生词本类型,0有道,1欧路
14 | dictionaryType: 0,
15 | autoSync: true,
16 | cookie: false,
17 | })
18 | }
19 |
20 |
21 | function setStyle(result) {
22 | let highlightCss = ".xqdd_highlight_new_word {background-color: " + result.highlightBackground + ";";
23 | let bubbleCss = ".xqdd_bubble {background-color: " + result.bubbleBackground + ";";
24 | if (result.highlightText.trim() !== "") {
25 | highlightCss += "color:" + result.highlightText + ";";
26 | bubbleCss += "color:" + result.bubbleText + ";";
27 | }
28 | highlightCss += "}";
29 | bubbleCss += "}";
30 |
31 | // 获取所有标签页
32 | chrome.tabs.query({}, function (tabs) {
33 | tabs.forEach(function (tab) {
34 | // 为每个标签页插入样式
35 | chrome.scripting.insertCSS({
36 | target: { tabId: tab.id },
37 | css: highlightCss + bubbleCss
38 | });
39 | });
40 | });
41 | }
42 |
43 | //初始化配置
44 | chrome.storage.local.get(["ttsVoices", "syncTime", "autoSync", "cookie", "dictionaryType"], function (result) {
45 | if (!result.ttsVoices) {
46 | initSettings();
47 | }
48 | if (result.autoSync && (new Date().getTime() - result.syncTime) > 60 * 60 * 24 * 1000) {
49 | console.log("同步中。。。")
50 | sync((msg) => {
51 | console.log(msg)
52 | }, result.dictionaryType)
53 | }
54 | });
55 |
56 | function syncSuccess(wordInfos, cookie, sendResponse, dictionaryType) {
57 | chrome.storage.local.set({ newWords: { wordInfos }, dictionaryType, cookie, syncTime: new Date().getTime() }, () => {
58 | sendResponse("同步成功");
59 | });
60 | }
61 |
62 | let sync = function (sendResponse, dictionaryType) {
63 | //同步有道词典
64 | if (dictionaryType == 0) {
65 | getCookie(cookie => {
66 | fetch("http://dict.youdao.com/wordbook/webapi/words?limit=100000000&offset=0")
67 | .then(res => res.json())
68 | .then(({ data }) => {
69 | console.log(data)
70 |
71 | let wordInfos = {};
72 | if (data.total === 0) {
73 | sendResponse("同步成功,但生词本无内容,若实际有内容,请尝试重新登录");
74 | return
75 | }
76 | data.itemList.forEach(w => {
77 | wordInfos[w.word.toLowerCase()] = w
78 | });
79 | syncSuccess(wordInfos, cookie, sendResponse, dictionaryType);
80 | }).catch(e => {
81 | sendResponse("网络错误或服务器出错,请检查网络后再试或重新登录");
82 | });
83 | })
84 | }
85 | //同步欧路词典
86 | else if (dictionaryType == 1) {
87 | syncEudic(sendResponse, dictionaryType);
88 | }
89 | };
90 |
91 |
92 | async function syncEudic(sendResponse, dictionaryType) {
93 | let start = 0;
94 | let wordInfos = {};
95 | let hasMoreData = true;
96 | let limit = 4000;
97 |
98 | while (hasMoreData) {
99 | try {
100 | const response = await fetch(`https://my.eudic.net/StudyList/WordsDataSource?start=${start}&length=${limit}`);
101 | const result = await response.json();
102 |
103 | if (result.data && result.data.length > 0) {
104 | result.data.forEach(item => {
105 | wordInfos[item.uuid.toLowerCase()] = {
106 | phonetic: item.phon,
107 | trans: item.exp,
108 | word: item.uuid,
109 | link: item.word,
110 | };
111 | });
112 |
113 | start += limit;
114 | await new Promise(resolve => setTimeout(resolve, 500));
115 | } else {
116 | hasMoreData = false;
117 | }
118 | } catch (e) {
119 | sendResponse("网络错误或服务器出错,请检查网络后再试或重新登录");
120 | return;
121 | }
122 | }
123 |
124 | if (Object.keys(wordInfos).length > 0) {
125 | syncSuccess(wordInfos, null, sendResponse, dictionaryType);
126 | } else {
127 | sendResponse("同步成功,但生词本无内容,若实际有内容,请尝试重新登录");
128 | }
129 | }
130 |
131 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
132 | let needResponse = true;
133 | if (request.type === "tts") {
134 | if (!!request.word && typeof request.word === "string") {
135 | chrome.storage.local.get(["ttsToggle", "ttsVoices"], function (result) {
136 | if (result.ttsToggle) {
137 | chrome.tts.speak(request.word, { ...result.ttsVoices });
138 | }
139 | })
140 | }
141 | } else if (request.type === "resetSettings") {
142 | initSettings()
143 | } else if (request.type === "setStyle") {
144 | chrome.storage.local.get(["highlightBackground", "highlightText", "bubbleBackground", "bubbleText"], function (result) {
145 | setStyle(result);
146 | })
147 | } else if (request.type === "sync") {
148 | needResponse = false;
149 | sync(sendResponse, request.dictionaryType);
150 | } else if (request.type === "delete") {
151 | needResponse = false;
152 | let wordData = request.wordData;
153 | let word = wordData.word;
154 | chrome.storage.local.get(["dictionaryType"], function (result) {
155 | if (result.dictionaryType == 0) {
156 | fetch(`http://dict.youdao.com/wordbook/webapi/delete?itemId=${wordData.itemId}`)
157 | } else if (result.dictionaryType == 1) {
158 | fetch("https://dict.eudic.net/Dicts/SetStarRating", {
159 | method: 'POST',
160 | headers: {
161 | 'Content-Type': 'application/json'
162 | },
163 | body: JSON.stringify({ rating: -1, word, lang: 'en' })
164 | })
165 | }
166 | })
167 | chrome.storage.local.get("newWords", function (result) {
168 | let wordInfos = result.newWords.wordInfos;
169 | delete wordInfos[word.toLowerCase()];
170 | chrome.storage.local.set({ newWords: { wordInfos } });
171 | sendResponse("删除成功,刷新页面后生效");
172 | });
173 | } else if (request.type === "count") {
174 | const id = sender.tab.id
175 | if (!wordCount[id]) {
176 | wordCount[id] = new Set()
177 | }
178 | const word = request.word.toLowerCase()
179 | if (!wordCount[id].has(word)) {
180 | wordCount[id].add(word)
181 | updateWordCount(id)
182 | }
183 | }
184 | if (needResponse) {
185 | sendResponse();
186 | }
187 | return true;
188 | // sendResponse('我是后台,我已收到你的消息:' + JSON.stringify(request));
189 | });
190 |
191 |
192 | function getCookie(callback) {
193 | chrome.storage.local.get("cookie", function (result) {
194 | if (!!result.cookie) {
195 | callback(result.cookie)
196 | } else {
197 | chrome.cookies.getAll({ url: "http://dict.youdao.com/wordbook/wordlist" }, cookies => {
198 | cookies.map(c => c.name + "=" + c.value).join(";")
199 | callback(cookies.map(c => c.name + "=" + c.value).join(";"))
200 | })
201 | }
202 | });
203 | }
204 |
205 |
206 | //处理单词计数
207 | let wordCount = {}
208 | let wordCountUrl = {}
209 | chrome.tabs.onUpdated.addListener(function (id, info, tab) {
210 | if (wordCountUrl[id] !== tab.url) {
211 | wordCountUrl[id] = tab.url
212 | if (wordCount[id]) {
213 | wordCount[id].clear();
214 | } else {
215 | wordCount[id] = new Set()
216 | }
217 | updateWordCount(id)
218 | }
219 | if (info.status === "complete") {
220 | updateWordCount(id)
221 | }
222 | })
223 |
224 |
225 | function updateWordCount(tabId) {
226 | if (wordCount[tabId]) {
227 | const count = wordCount[tabId].size;
228 |
229 | chrome.action.getBadgeText({ tabId }, function (countStr) {
230 | if (count === 0 && (!countStr || countStr === "")) {
231 | // 如果当前计数为0且徽章文字为空,则什么都不做
232 | return;
233 | }
234 | // 将徽章文字设置为当前的单词计数
235 | chrome.action.setBadgeText({
236 | text: count.toString(),
237 | tabId
238 | });
239 | });
240 | }
241 | }
242 |
243 | chrome.tabs.onRemoved.addListener(function (tabId) {
244 | if (wordCount[tabId]) {
245 | wordCount[tabId].clear()
246 | delete wordCount[tabId]
247 | delete wordCountUrl[tabId]
248 | }
249 | })
250 |
--------------------------------------------------------------------------------
/popup/popup.js:
--------------------------------------------------------------------------------
1 | let ttsVoices = $("#tts_voices");
2 | let ttsToggle = $("#tts_toggle");
3 | let highlightBackground = $("#highlight_background");
4 | let highlightText = $("#highlight_text");
5 | let highlightTemplate = $("#highlight_template");
6 | let bubbleBackground = $("#bubble_background");
7 | let bubbleTemplate = $("#bubble_template");
8 | let bubbleText = $("#bubble_text");
9 | let toggle = $("#toggle");
10 | let reset = $("#reset");
11 | let wordStatus = $("#word_status");
12 | let xmlFile = $("#file");
13 | let syncButton = $(".sync");
14 | let autoSync = $("#auto_sync");
15 | let youdaoLoginATag = $("#youdao_login");
16 | let oluLoginATag = $("#olu_login");
17 |
18 | //日期加强
19 |
20 | // 对Date的扩展,将 Date 转化为指定格式的String
21 | // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
22 | // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
23 | // 例子:
24 | // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
25 | // (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
26 | Date.prototype.format = function (fmt) { //author: meizz
27 | var o = {
28 | "M+": this.getMonth() + 1, //月份
29 | "d+": this.getDate(), //日
30 | "h+": this.getHours(), //小时
31 | "m+": this.getMinutes(), //分
32 | "s+": this.getSeconds(), //秒
33 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度
34 | "S": this.getMilliseconds() //毫秒
35 | };
36 | if (/(y+)/.test(fmt))
37 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
38 | for (var k in o)
39 | if (new RegExp("(" + k + ")").test(fmt))
40 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
41 | return fmt;
42 | }
43 |
44 |
45 | function getRandomColor() {
46 | var rand = Math.floor(Math.random() * 0xFFFFFF).toString(16);
47 | if (rand.length == 6) {
48 | return rand;
49 | } else {
50 | return getRandomColor();
51 | }
52 | }
53 |
54 | //单词样式相关
55 | function initStyle() {
56 | chrome.storage.local.get([
57 | "highlightBackground"
58 | , "highlightText"
59 | , "bubbleBackground"
60 | , "bubbleText"], function (result) {
61 | highlightBackground.val(result.highlightBackground)
62 | highlightText.val(result.highlightText)
63 | highlightTemplate.css("background-color", result.highlightBackground)
64 | if (result.highlightText.trim() !== "") {
65 | highlightTemplate.css("color", result.highlightText)
66 | }
67 | bubbleBackground.val(result.bubbleBackground)
68 | bubbleText.val(result.bubbleText)
69 | bubbleTemplate.css("background-color", result.bubbleBackground)
70 | if (result.bubbleText.trim() !== "") {
71 | bubbleTemplate.css("color", result.bubbleText)
72 | }
73 | chrome.runtime.sendMessage({ type: "setStyle" })
74 | })
75 | }
76 |
77 |
78 | function updateWordStatus(color, err) {
79 | let status = "";
80 | if (err) {
81 | status = "导入失败"
82 | wordStatus.css("color", "#" + color);
83 | } else {
84 | chrome.storage.local.get(["newWords", "syncTime", "dictionaryType"], function (result) {
85 | if (result.newWords) {
86 | status = Object.keys(result.newWords.wordInfos).length + "个词"
87 | if (!!color) {
88 | wordStatus.css("color", "#" + color);
89 | }
90 | status += ", 同步于" + (new Date(result.syncTime)).format("yyyy-MM-dd hh:mm:ss")
91 | if (result.dictionaryType == 0) {
92 | status = "有道, " + status
93 | } else if (result.dictionaryType == 1) {
94 | status = "欧路, " + status
95 | }
96 | } else {
97 | status = "未导入单词, 请登陆相关平台后点击同步单词进行同步"
98 | }
99 | wordStatus.text(status)
100 | })
101 | }
102 | wordStatus.text(status)
103 | }
104 |
105 | //配置
106 | function initSettings() {
107 | chrome.storage.local.get([
108 | "ttsToggle"
109 | , "ttsVoices"
110 | , "autoSync"
111 | , "syncTime"
112 | , "cookie"
113 | , "dictionaryType"
114 | , "toggle"
115 | ], function (result) {
116 | //总开关
117 | toggle.prop("checked", result.toggle)
118 | //发音开关
119 | ttsToggle.prop("checked", result.ttsToggle)
120 | //自动同步开关
121 | autoSync.prop("checked", result.autoSync)
122 | //发音人员
123 | chrome.tts.getVoices(
124 | function (voices) {
125 | let oldVoice = result.ttsVoices
126 | let index = 1;
127 | let isSelected = false
128 | ttsVoices.empty()
129 | for (let i = 0; i < voices.length; i++) {
130 | let voice = voices[i];
131 | delete voice.eventTypes;
132 | if (!voice.lang
133 | || voice.lang.toLowerCase().startsWith("en")
134 | || voice.lang.toLowerCase().startsWith("xx")) {
135 | let option = $(""));
153 | }
154 | });
155 | //高亮
156 | initStyle();
157 | //同步状态
158 | updateWordStatus()
159 | })
160 | }
161 |
162 |
163 | xmlFile.on("change", function () {
164 | let file = this.files[0]
165 | if (file) {
166 | let reader = new FileReader()
167 | reader.onload = function () {
168 | try {
169 | let xml = $($.parseXML(this.result))
170 | let wordInfos = {}
171 | let transList = [];
172 | let phoneticList = [];
173 | // var originWordList = [];
174 | // var wordList = [];
175 | var items = xml.find("item");
176 | items.each(function (i, val) {
177 | let node = $(val)
178 | let word = node.find("word").text()
179 | // originWordList.push(word)
180 | // wordList.push(word.toLowerCase())
181 | wordInfos[word.toLowerCase()] = {
182 | word,
183 | trans: node.find("trans").text(),
184 | phonetic: node.find("phonetic").text()
185 | }
186 | })
187 | chrome.storage.local.set({ newWords: { wordInfos } })
188 | //提示导入成功
189 | // chrome.notifications.create({
190 | // type: "basic",
191 | // title: "test",
192 | // message: "解析单词本成功"
193 | // })
194 | updateWordStatus(getRandomColor(), false)
195 | // chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
196 | // chrome.tabs.sendMessage(tabs[0].id, {type: "importSuccess"});
197 | // });
198 | } catch (err) {
199 | updateWordStatus(getRandomColor(), true)
200 | } finally {
201 | xmlFile.val("");
202 | }
203 | }
204 | reader.readAsText(file)
205 | }
206 | })
207 |
208 |
209 | //事件监听
210 | ttsVoices.on("click", function () {
211 | let val = $("#tts_voices option:selected").val();
212 | if (val && val !== "" && val !== "无") {
213 | let ttsVoices = JSON.parse(val);
214 | chrome.storage.local.set({ ttsVoices })
215 | }
216 | })
217 | ttsToggle.on("click", function () {
218 | chrome.storage.local.set({ ttsToggle: ttsToggle.prop("checked") })
219 | })
220 | toggle.on("click", function () {
221 | chrome.storage.local.set({ toggle: toggle.prop("checked") })
222 | })
223 | autoSync.on("click", function () {
224 | chrome.storage.local.set({ autoSync: autoSync.prop("checked") })
225 | })
226 | highlightText.on("input", function () {
227 | chrome.storage.local.set({ highlightText: highlightText.val() }, function () {
228 | initStyle()
229 | })
230 | })
231 | highlightBackground.on("input", function () {
232 | chrome.storage.local.set({ highlightBackground: highlightBackground.val() }, function () {
233 | initStyle()
234 | })
235 | })
236 | bubbleText.on("input", function () {
237 | chrome.storage.local.set({ bubbleText: bubbleText.val() }, function () {
238 | initStyle()
239 | })
240 | })
241 | bubbleBackground.on("input", function () {
242 | chrome.storage.local.set({ bubbleBackground: bubbleBackground.val() }, function () {
243 | initStyle()
244 | })
245 | })
246 | reset.on("click", function () {
247 | if (window.confirm("确认恢复默认设置?")) {
248 | chrome.runtime.sendMessage({ type: "resetSettings" }, function () {
249 | initSettings()
250 | })
251 | }
252 | })
253 | $("#help").on("click", function () {
254 | chrome.tabs.create({ url: 'https://github.com/XQDD/highlight_new_words' });
255 | })
256 | $("#moreVoices").on("click", function () {
257 | chrome.tabs.create({ url: 'https://chrome.google.com/webstore/detail/speakit/pgeolalilifpodheeocdmbhehgnkkbak' });
258 | })
259 | youdaoLoginATag.on("click", function () {
260 | chrome.tabs.create({ url: 'http://dict.youdao.com/wordbook/wordlist' });
261 | })
262 | oluLoginATag.on("click", function () {
263 | chrome.tabs.create({ url: 'https://my.eudic.net/studylist' });
264 | })
265 | syncButton.click(function () {
266 | let clickedSyncButton = $(this)
267 | clickedSyncButton.attr("disabled", "")
268 | chrome.runtime.sendMessage({ type: "sync", dictionaryType: $(this).attr("dictionaryType") }, function (msg) {
269 | if (msg) {
270 | alert(msg)
271 | }
272 | initSettings()
273 | clickedSyncButton.removeAttr("disabled")
274 | })
275 | })
276 |
277 | $(".color-scheme-button").on("click", function () {
278 | const bgColor = $(this).data("bg");
279 | const textColor = $(this).data("text");
280 | highlightBackground.val(bgColor);
281 | highlightText.val(textColor);
282 | bubbleBackground.val(bgColor);
283 | bubbleText.val(textColor);
284 | chrome.storage.local.set({
285 | highlightBackground: bgColor,
286 | highlightText: textColor,
287 | bubbleBackground: bgColor,
288 | bubbleText: textColor
289 | }, function () {
290 | initStyle();
291 | });
292 | });
293 |
294 |
295 | initSettings()
296 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/content_scripts/highlight.js:
--------------------------------------------------------------------------------
1 | //生词本
2 | var newWords;
3 | //当前要显示的节点
4 | var currNode
5 | //鼠标节点(实时)
6 | var mouseNode
7 | //已经显示了的节点
8 | var showedNode
9 | //是否允许隐藏气泡
10 | var isAllowHideBubble = true
11 | //气泡显示/隐藏延迟时间(ms)
12 | var delayed = 100
13 | //生词信息列表
14 | var currWord
15 | var currWordData
16 |
17 | $(function () {
18 | init()
19 | })
20 |
21 |
22 | /**
23 | * 初始化
24 | */
25 | function init() {
26 | //从localstorege获取生词列表,高亮所有匹配的节点
27 | chrome.storage.local.get(["toggle"], function (r) {
28 | if (r.toggle) {
29 | chrome.storage.local.get(["newWords"], function (result) {
30 | // var before = new Date().getTime()
31 | newWords = result.newWords;
32 | highlight(textNodesUnder(document.body))
33 | //console.log("解析总耗时:" + (new Date().getTime() - before) + " ms")
34 |
35 | //在插入节点时修改
36 | // Create an observer instance
37 | const observer = new MutationObserver(onNodeInserted);
38 | // Configuration object for the observer
39 | const config = { childList: true, subtree: true };
40 | // Start observing a target node (document.body in this case)
41 | observer.observe(document.body, config);
42 | chrome.runtime.sendMessage({ type: "setStyle" })
43 | })
44 |
45 | }
46 | })
47 |
48 | //创建鼠标悬浮气泡
49 | createBubble();
50 |
51 | //监听xml导入成功消息
52 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
53 | if (request.type == "importSuccess") {
54 | alert("导入生词本成功")
55 | }
56 | })
57 |
58 |
59 | }
60 |
61 | /**
62 | * 创建鼠标悬浮气泡
63 | */
64 | function createBubble() {
65 | //创建添加到body中
66 | var div = $("