diff --git a/src/background.js b/src/background.js index 792fe3bc..c53f5bbb 100644 --- a/src/background.js +++ b/src/background.js @@ -14,6 +14,7 @@ var introSiteUrl = addInstallUrl(introSiteUrl); addUninstallUrl(util.getReviewUrl()); +addCopyRequestListener(); injectContentScriptForAllTab(); getSetting(); @@ -57,7 +58,7 @@ browser.runtime.onMessage.addListener(function (request, sender, sendResponse) { sendResponse({}); } else if (request.type === "recordTooltipText") { recordHistory(request); - updateContext(request); + updateCopyContext(request); sendResponse({}); } else if (request.type === "removeContextAll") { removeContextAll(); @@ -172,24 +173,23 @@ async function openPDFViewer(url, tabId) { }); } -// ================= context menu -async function updateContext(request) { +// ================= Copy + +function addCopyRequestListener() { + // context menu handler for copy + util.addContextListener("copy", requestCopyForTargetText); + //command shortcut key handler for copy + util.addCommandListener("copy-translated-text", requestCopyForTargetText); +} + +async function updateCopyContext(request) { // remove previous await removeContext("copy"); //create new menu browser.contextMenus.create({ id: "copy", - title: "Copy : " + truncate(request.targetText, 20), - contexts: [ - "page", - "frame", - "selection", - "link", - "editable", - "image", - "video", - "audio", - ], + title: "Copy : " + util.truncate(request.targetText, 20), + contexts: ["all"], visible: true, }); recentTranslated = request; @@ -204,46 +204,12 @@ async function removeContextAll(id) { await browser.contextMenus.removeAll(); } -browser.contextMenus.onClicked.addListener((info, tab) => { - if (info.menuItemId == "copy") { - copyOntab(tab, recentTranslated.targetText); - } -}); - -function copyText(text) { - navigator.clipboard.writeText(text); -} - -function runFunctionOnTab(tabId, func, args) { - browser.scripting.executeScript({ - target: { tabId: tabId }, - func: func, - args: args, - }); -} - -function copyOntab(tab, text) { - runFunctionOnTab(tab.id, copyText, [text]); +function requestCopyForTargetText() { + requestCopyOnTab(recentTranslated.targetText); } -function truncate(str, n) { - return str.length > n ? str.slice(0, n - 1) + "..." : str; -} - -//command shortcut key===================================== -browser.commands.onCommand.addListener((command) => { - (async () => { - if (command == "copy-translated-text") { - var recentTab = await getCurrentTab(); - copyOntab(recentTab, recentTranslated.targetText); - } - })(); -}); - -async function getCurrentTab() { - let queryOptions = { active: true, lastFocusedWindow: true }; - let [tab] = await browser.tabs.query(queryOptions); - return tab; +function requestCopyOnTab(text) { + util.sendMessageToCurrentTab({ type: "CopyRequest", text }); } // ================= contents script reinjection after upgrade or install diff --git a/src/contentScript.js b/src/contentScript.js index 1d46cc60..73a40902 100644 --- a/src/contentScript.js +++ b/src/contentScript.js @@ -29,14 +29,6 @@ var destructionEvent = "destructmyextension_MouseTooltipTranslator"; // + chrome const controller = new AbortController(); const { signal } = controller; var mouseoverInterval; -var rtlLangList = [ - "ar", //Arabic - "iw", //Hebrew - "ku", //Kurdish - "fa", //Persian - "ur", //Urdu - "yi", //Yiddish -]; //right to left language system list var writingField = 'input[type="text"], input[type="search"], input:not([type]), textarea, [contenteditable="true"], [role=textbox], [spellcheck]'; var isYoutubeDetected = false; @@ -53,6 +45,7 @@ $(async function initMouseTooltipTranslator() { checkYoutube(); addElementEnv(); //add tooltip container applyStyleSetting(); //add tooltip style + addBackgroundListener(); loadEventListener(); //load event listener to detect mouse move startMouseoverDetector(); // start current mouseover text detector startTextSelectDetector(); // start current text select detector @@ -196,7 +189,7 @@ function showTooltip(text, lang) { hideTooltip(); //reset tooltip arrow checkTooltipContainer(); setTooltipPosition("showTooltip"); - applyLangAlignment(lang); + applyRtl(lang); tooltipContainer.attr("data-original-title", text); //place text on tooltip tooltipContainer.tooltip("show"); } @@ -205,9 +198,8 @@ function hideTooltip() { tooltipContainer.tooltip("hide"); } -function applyLangAlignment(lang) { - var isRtl = rtlLangList.includes(lang) ? "rtl" : "ltr"; - tooltipContainer.attr("dir", isRtl); +function applyRtl(lang) { + tooltipContainer.attr("dir", util.isRtl(lang)); } function checkTooltipContainer() { @@ -330,7 +322,7 @@ function getWritingText() { return writingText; } -//event Listener - detect mouse move, key press, mouse press, tab switch========================================================================================== +// Listener - detect mouse move, key press, mouse press, tab switch========================================================================================== function loadEventListener() { //use mouse position for tooltip position addEventHandler("mousemove", handleMousemove); @@ -444,21 +436,17 @@ function checkMouseOnceMoved(x, y) { return mouseMoved; } -//send to background.js for background processing =========================================================================== - -async function sendMessage(message) { - try { - return await chrome.runtime.sendMessage(message); - } catch (e) { - if (e.message != "Extension context invalidated.") { - console.log(e); - } - } - return {}; +function addBackgroundListener() { + //handle copy + util.addMessageListener("CopyRequest", (message) => { + util.copyTextToClipboard(message.text); + }); } +//send to background.js for background processing =========================================================================== + async function requestTranslate(word, translateSource, translateTarget) { - return await sendMessage({ + return await util.sendMessage({ type: "translate", word: word, translateSource, @@ -467,7 +455,7 @@ async function requestTranslate(word, translateSource, translateTarget) { } async function requestTTS(sourceText, sourceLang, targetText, targetLang) { - return await sendMessage({ + return await util.sendMessage({ type: "tts", sourceText, sourceLang, @@ -477,7 +465,7 @@ async function requestTTS(sourceText, sourceLang, targetText, targetLang) { } async function requestStopTTS() { - return await sendMessage({ + return await util.sendMessage({ type: "stopTTS", }); } @@ -490,7 +478,7 @@ async function requestRecordTooltipText( targetLang, actionType ) { - return await sendMessage({ + return await util.sendMessage({ type: "recordTooltipText", sourceText, targetText, @@ -501,7 +489,7 @@ async function requestRecordTooltipText( } async function requestRemoveAllContext() { - return await sendMessage({ + return await util.sendMessage({ type: "removeContextAll", }); } diff --git a/src/util/index.js b/src/util/index.js index c7b0e5f7..ad1ee6e5 100644 --- a/src/util/index.js +++ b/src/util/index.js @@ -45,6 +45,15 @@ var defaultData = { const PARENT_TAGS_TO_EXCLUDE = ["STYLE", "SCRIPT", "TITLE"]; +var rtlLangList = [ + "ar", //Arabic + "iw", //Hebrew + "ku", //Kurdish + "fa", //Persian + "ur", //Urdu + "yi", //Yiddish +]; //right to left language system list + var reviewUrlJson = { nnodgmifnfgkolmakhcfkkbbjjcobhbl: "https://microsoftedge.microsoft.com/addons/detail/mouse-tooltip-translator/nnodgmifnfgkolmakhcfkkbbjjcobhbl", @@ -293,6 +302,14 @@ export function filterWord(word) { return word; } +export function truncate(str, n) { + return str.length > n ? str.slice(0, n - 1) + "..." : str; +} + +export function copyTextToClipboard(text) { + navigator.clipboard.writeText(text); +} + // inject ================================= export function injectScript(scriptUrl) { return new Promise((resolve) => { @@ -344,6 +361,10 @@ export function getBase64(url) { // remain =================== +export function isRtl(lang) { + return rtlLangList.includes(lang) ? "rtl" : "ltr"; +} + export function checkInDevMode() { try { if (process.env.NODE_ENV == "development") { @@ -353,6 +374,17 @@ export function checkInDevMode() { return false; } +export function getReviewUrl() { + var extId = + browser.runtime.id in reviewUrlJson + ? browser.runtime.id + : "hmigninkgibhdckiaphhmbgcghochdjc"; + + return reviewUrlJson[extId]; +} + +// browser Listener handler======================== + export function postMessage(data) { if (self == top) { window.postMessage(data, "*"); @@ -362,11 +394,43 @@ export function postMessage(data) { } } -export function getReviewUrl() { - var extId = - browser.runtime.id in reviewUrlJson - ? browser.runtime.id - : "hmigninkgibhdckiaphhmbgcghochdjc"; +export async function sendMessage(message) { + try { + return await browser.runtime.sendMessage(message); + } catch (e) { + if (e.message != "Extension context invalidated.") { + console.log(e); + } + } + return {}; +} - return reviewUrlJson[extId]; +export function sendMessageToCurrentTab(message) { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, message); + }); +} + +export function addMessageListener(type, handler) { + browser.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.type == type) { + handler(message); + } + }); +} + +export function addContextListener(type, handler) { + browser.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId == type) { + handler(); + } + }); +} + +export function addCommandListener(type, handler) { + browser.commands.onCommand.addListener((command) => { + if (command == type) { + handler(); + } + }); }