10 |
11 |
Extension Options
12 |
13 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/options/options.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_LANGUAGE = 'en',
2 | DEFAULT_TRIGGER_KEY = 'none',
3 | IS_HISTORY_ENABLED_BY_DEFAULT = true,
4 |
5 | SAVE_STATUS = document.querySelector("#save-status"),
6 |
7 | SAVE_OPTIONS_BUTTON = document.querySelector("#save-btn"),
8 | RESET_OPTIONS_BUTTON = document.querySelector("#reset-btn"),
9 |
10 | CLEAR_HISTORY_BUTTON = document.querySelector("#clear-history-btn"),
11 | DOWNLOAD_HISTORY_BUTTON = document.querySelector("#download-history-btn"),
12 |
13 | OS_MAC = 'mac',
14 |
15 | KEY_COMMAND = 'Command',
16 | KEY_META = 'meta';
17 |
18 |
19 |
20 | function saveOptions(e) {
21 | browser.storage.local.set({
22 | language: document.querySelector("#language-selector").value,
23 | interaction: {
24 | dblClick: {
25 | key: document.querySelector("#popup-dblclick-key").value
26 | }
27 | },
28 | history: {
29 | enabled: document.querySelector("#store-history-checkbox").checked
30 | }
31 | }).then(showSaveStatusAnimation);
32 |
33 | e.preventDefault();
34 | }
35 |
36 | function restoreOptions() {
37 | let storageItem = browser.storage.local.get();
38 |
39 | storageItem.then((results) => {
40 | let language = results.language,
41 | interaction = results.interaction || {},
42 | history = results.history || { enabled: IS_HISTORY_ENABLED_BY_DEFAULT },
43 | definitions = results.definitions || {};
44 |
45 | // language
46 | document.querySelector("#language-selector").value = language || DEFAULT_LANGUAGE;
47 |
48 | // interaction
49 | // document.querySelector("#popup-dblclick-checkbox").checked = interaction.dblClick.enabled;
50 | document.querySelector("#popup-dblclick-key").value = (interaction.dblClick && interaction.dblClick.key) || DEFAULT_TRIGGER_KEY;
51 |
52 | // document.querySelector("#popup-select-checkbox").checked = interaction.select.enabled;
53 | // document.querySelector("#popup-select-key").value = interaction.select.key;
54 |
55 | // history
56 | document.querySelector("#store-history-checkbox").checked = history.enabled;
57 | document.querySelector("#num-words-in-history").innerText = Object.keys(definitions).length;
58 | });
59 | }
60 |
61 | function downloadHistory (e) {
62 | let fileContent = ""
63 | storageItem = browser.storage.local.get("definitions"),
64 | anchorTag = document.querySelector("#download-history-link");
65 |
66 | storageItem.then((results) => {
67 | let definitions = results.definitions || {};
68 |
69 | for (definition in definitions) {
70 | if (!definitions.hasOwnProperty(definition)) { return; }
71 |
72 | fileContent += definition;
73 | fileContent += "\t";
74 | fileContent += "\t";
75 | fileContent += definitions[definition];
76 | fileContent += "\n";
77 | }
78 |
79 | anchorTag.href = window.URL.createObjectURL(new Blob([fileContent],{
80 | type: "text/plain"
81 | }));
82 |
83 | anchorTag.dispatchEvent(new MouseEvent('click'));
84 | });
85 |
86 | e.preventDefault();
87 | }
88 |
89 | function resetOptions (e) {
90 | browser.storage.local.set({
91 | language: DEFAULT_LANGUAGE,
92 | interaction: {
93 | dblClick: {
94 | key: DEFAULT_TRIGGER_KEY
95 | }
96 | },
97 | history: {
98 | enabled: IS_HISTORY_ENABLED_BY_DEFAULT
99 | }
100 | }).then(restoreOptions);
101 |
102 | e.preventDefault();
103 | }
104 |
105 | function clearHistory(e) {
106 | browser.storage.local.set({ definitions: {} });
107 |
108 | e.preventDefault();
109 | }
110 |
111 | function showSaveStatusAnimation () {
112 | SAVE_STATUS.style.setProperty("-webkit-transition", "opacity 0s ease-out");
113 | SAVE_STATUS.style.opacity = 1;
114 | window.setTimeout(function() {
115 | SAVE_STATUS.style.setProperty("-webkit-transition", "opacity 0.4s ease-out");
116 | SAVE_STATUS.style.opacity = 0
117 | }, 1500);
118 | }
119 |
120 | document.addEventListener('DOMContentLoaded', restoreOptions);
121 |
122 | CLEAR_HISTORY_BUTTON.addEventListener("click", clearHistory);
123 | DOWNLOAD_HISTORY_BUTTON.addEventListener("click", downloadHistory);
124 |
125 | SAVE_OPTIONS_BUTTON.addEventListener("click", saveOptions);
126 | RESET_OPTIONS_BUTTON.addEventListener("click", resetOptions);
127 |
128 | if (window.navigator.platform.toLowerCase().includes(OS_MAC)) {
129 | document.getElementById("popup-dblclick-key-ctrl").textContent = KEY_COMMAND;
130 | document.getElementById("popup-dblclick-key-ctrl").value = KEY_META;
131 | }
132 |
--------------------------------------------------------------------------------
/content_scripts/dictionary.js:
--------------------------------------------------------------------------------
1 | var DEFAULT_LANGUAGE = 'en',
2 | DEFAULT_TRIGGER_KEY = 'none',
3 |
4 | LANGUAGE,
5 | TRIGGER_KEY;
6 |
7 | function showMeaning (event){
8 | var createdDiv,
9 | info = getSelectionInfo(event);
10 |
11 | if (!info) { return; }
12 |
13 | retrieveMeaning(info)
14 | .then((response) => {
15 | if (!response.content) { return noMeaningFound(createdDiv); }
16 |
17 | appendToDiv(createdDiv, response.content);
18 | });
19 |
20 | // Creating this div while we are fetching meaning to make extension more fast.
21 | createdDiv = createDiv(info);
22 | }
23 |
24 |
25 | function getSelectionInfo(event) {
26 | var word;
27 | var boundingRect;
28 |
29 | if (window.getSelection().toString().length > 1) {
30 | word = window.getSelection().toString();
31 | boundingRect = getSelectionCoords(window.getSelection());
32 | } else {
33 | return null;
34 | }
35 |
36 | var top = boundingRect.top + window.scrollY,
37 | bottom = boundingRect.bottom + window.scrollY,
38 | left = boundingRect.left + window.scrollX;
39 |
40 | if (boundingRect.height == 0) {
41 | top = event.pageY;
42 | bottom = event.pageY;
43 | left = event.pageX;
44 | }
45 |
46 | return {
47 | top: top,
48 | bottom: bottom,
49 | left: left,
50 | word: word,
51 | clientY: event.clientY,
52 | height: boundingRect.height
53 | };
54 | }
55 |
56 | function retrieveMeaning(info){
57 | return browser.runtime.sendMessage({ word: info.word, lang: LANGUAGE, time: Date.now() });
58 | }
59 |
60 | function createDiv(info) {
61 | var hostDiv = document.createElement("div");
62 |
63 | hostDiv.className = "dictionaryDiv";
64 | hostDiv.style.left = info.left -10 + "px";
65 | hostDiv.style.position = "absolute";
66 | hostDiv.style.zIndex = "1000000"
67 | hostDiv.attachShadow({mode: 'open'});
68 |
69 | var shadow = hostDiv.shadowRoot;
70 | var style = document.createElement("style");
71 | //style.textContent = "*{ all: initial}";
72 | style.textContent = ".mwe-popups{background:#fff;position:absolute;z-index:110;-webkit-box-shadow:0 30px 90px -20px rgba(0,0,0,0.3),0 0 1px #a2a9b1;box-shadow:0 30px 90px -20px rgba(0,0,0,0.3),0 0 1px #a2a9b1;padding:0;font-size:14px;min-width:300px;border-radius:2px}.mwe-popups.mwe-popups-is-not-tall{width:320px}.mwe-popups .mwe-popups-container{color:#222;margin-top:-9px;padding-top:9px;text-decoration:none}.mwe-popups.mwe-popups-is-not-tall .mwe-popups-extract{min-height:40px;max-height:140px;overflow:hidden;margin-bottom:47px;padding-bottom:0}.mwe-popups .mwe-popups-extract{margin:16px;display:block;color:#222;text-decoration:none;position:relative} .mwe-popups.flipped_y:before{content:'';position:absolute;border:8px solid transparent;border-bottom:0;border-top: 8px solid #a2a9b1;bottom:-8px;left:10px}.mwe-popups.flipped_y:after{content:'';position:absolute;border:11px solid transparent;border-bottom:0;border-top:11px solid #fff;bottom:-7px;left:7px} .mwe-popups.mwe-popups-no-image-tri:before{content:'';position:absolute;border:8px solid transparent;border-top:0;border-bottom: 8px solid #a2a9b1;top:-8px;left:10px}.mwe-popups.mwe-popups-no-image-tri:after{content:'';position:absolute;border:11px solid transparent;border-top:0;border-bottom:11px solid #fff;top:-7px;left:7px} .audio{background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVQ4y2P4//8/AyUYQhAH3gNxA7IAIQPmo/H3g/QA8XkgFiBkwHyoYnRQABVfj88AmGZcTuuHyjlgMwBZM7IE3NlQGhQe65EN+I8Dw8MLGgYoFpFqADK/YUAMwOsFigORatFIlYRElaRMWmaiBAMAp0n+3U0kqkAAAAAASUVORK5CYII=);background-position: center;background-repeat: no-repeat;cursor:pointer;margin-left: 8px;opacity: 0.5; width: 16px; display: inline-block;} .audio:hover {opacity: 1;}";
73 | shadow.appendChild(style);
74 |
75 | var encapsulateDiv = document.createElement("div");
76 | encapsulateDiv.style = "all: initial; text-shadow: transparent 0px 0px 0px, rgba(0,0,0,1) 0px 0px 0px !important;";
77 | shadow.appendChild(encapsulateDiv);
78 |
79 |
80 | var popupDiv = document.createElement("div");
81 | popupDiv.style = "font-family: arial,sans-serif; border-radius: 12px; border: 1px solid #a2a9b1; box-shadow: 0 0 17px rgba(0,0,0,0.5)";
82 | encapsulateDiv.appendChild(popupDiv);
83 |
84 |
85 | var contentContainer = document.createElement("div");
86 | contentContainer.className = "mwe-popups-container";
87 | popupDiv.appendChild(contentContainer);
88 |
89 |
90 |
91 | var content = document.createElement("div");
92 | content.className = "mwe-popups-extract";
93 | content.style = "line-height: 1.4; margin-top: 0px; margin-bottom: 11px; max-height: none";
94 | contentContainer.appendChild(content);
95 |
96 |
97 | var heading = document.createElement("h3");
98 | heading.style = "margin-block-end: 0px; display:inline-block;";
99 | heading.textContent = "Searching";
100 |
101 | var meaning = document.createElement("p");
102 | meaning.style = "margin-top: 10px";
103 | meaning.textContent = "Please Wait...";
104 |
105 | var audio = document.createElement("div");
106 | audio.className = "audio";
107 | audio.innerHTML = " ";
108 | audio.style.display = "none";
109 |
110 | var moreInfo =document.createElement("a");
111 | moreInfo.href = `https://www.google.com/search?hl=${LANGUAGE}&q=define+${info.word}`;
112 | moreInfo.style = "float: right; text-decoration: none;"
113 | moreInfo.target = "_blank";
114 |
115 | content.appendChild(heading);
116 | content.appendChild(audio);
117 | content.appendChild(meaning);
118 | content.appendChild(moreInfo);
119 | document.body.appendChild(hostDiv);
120 |
121 | if(info.clientY < window.innerHeight/2){
122 | popupDiv.className = "mwe-popups mwe-popups-no-image-tri mwe-popups-is-not-tall";
123 | hostDiv.style.top = info.bottom + 10 + "px";
124 | if(info.height == 0){
125 | hostDiv.style.top = parseInt(hostDiv.style.top) + 8 + "px";
126 | }
127 | } else {
128 | popupDiv.className = "mwe-popups flipped_y mwe-popups-is-not-tall";
129 | hostDiv.style.top = info.top - 10 - popupDiv.clientHeight + "px";
130 |
131 | if(info.height == 0){
132 | hostDiv.style.top = parseInt(hostDiv.style.top) - 8 + "px";
133 | }
134 | }
135 |
136 | return {
137 | heading,
138 | meaning,
139 | moreInfo,
140 | audio
141 | };
142 |
143 | }
144 |
145 | function getSelectionCoords(selection) {
146 | var oRange = selection.getRangeAt(0); //get the text range
147 | var oRect = oRange.getBoundingClientRect();
148 | return oRect;
149 | }
150 |
151 | function appendToDiv(createdDiv, content){
152 | var hostDiv = createdDiv.heading.getRootNode().host;
153 | var popupDiv = createdDiv.heading.getRootNode().querySelectorAll("div")[1];
154 |
155 | var heightBefore = popupDiv.clientHeight;
156 | createdDiv.heading.textContent = content.word;
157 | createdDiv.meaning.textContent = content.meaning;
158 | createdDiv.moreInfo.textContent = "More »";
159 |
160 | var heightAfter = popupDiv.clientHeight;
161 | var difference = heightAfter - heightBefore;
162 |
163 |
164 | if(popupDiv.classList.contains("flipped_y")){
165 | hostDiv.style.top = parseInt(hostDiv.style.top) - difference + 1 + "px";
166 | }
167 |
168 | if(content.audioSrc){
169 | var sound = document.createElement("audio");
170 | sound.src = content.audioSrc;
171 | createdDiv.audio.style.display = "inline-block";
172 | createdDiv.audio.addEventListener("click", function(){
173 | sound.play();
174 | });
175 | }
176 | }
177 |
178 | function noMeaningFound (createdDiv){
179 | createdDiv.heading.textContent = "Sorry";
180 | createdDiv.meaning.textContent = "No definition found.";
181 | }
182 |
183 | function removeMeaning(event){
184 | var element = event.target;
185 | if(!element.classList.contains("dictionaryDiv")){
186 | document.querySelectorAll(".dictionaryDiv").forEach(function(Node){
187 | Node.remove();
188 | });
189 | }
190 | }
191 |
192 | document.addEventListener('dblclick', ((e) => {
193 | if (TRIGGER_KEY === 'none') {
194 | return showMeaning(e);
195 | }
196 |
197 | //e has property altKey, shiftKey, cmdKey representing they key being pressed while double clicking.
198 | if(e[`${TRIGGER_KEY}Key`]) {
199 | return showMeaning(e);
200 | }
201 |
202 | return;
203 | }));
204 |
205 | document.addEventListener('click', removeMeaning);
206 |
207 | (function () {
208 | let storageItem = browser.storage.local.get();
209 |
210 | storageItem.then((results) => {
211 | let interaction = results.interaction || { dblClick: { key: DEFAULT_TRIGGER_KEY }};
212 |
213 | LANGUAGE = results.language || DEFAULT_LANGUAGE;
214 | TRIGGER_KEY = interaction.dblClick.key;
215 | });
216 | })();
217 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.