From 41cc30b9f1a22c5c789d415827a2ae7161843aae Mon Sep 17 00:00:00 2001 From: wareya Date: Tue, 12 Dec 2017 18:53:17 -0500 Subject: [PATCH] Add a built in reader page with a clipboard hook --- background-script.js | 57 +++++++++++++++++++++++++--------- manifest.json | 8 +++-- options.html | 4 ++- options.js | 14 +++++++++ reader.html | 26 ++++++++++++++++ reader.js | 74 ++++++++++++++++++++++++++++++++++++++++++++ texthook.js | 62 +++++++++++++++++++++++++++---------- 7 files changed, 211 insertions(+), 34 deletions(-) create mode 100644 reader.html create mode 100644 reader.js diff --git a/background-script.js b/background-script.js index ddc769b..deb7a2e 100644 --- a/background-script.js +++ b/background-script.js @@ -741,18 +741,6 @@ function lookup_indirect(text, time) } } -browser.runtime.onMessage.addListener((req, sender, sendResponse) => -{ - if (req.type == "search") - { - sendResponse(lookup_indirect(req.text, req.time)); - } - else - { - return; - } -}); - async function update_icon(enabled) { if(enabled) @@ -783,16 +771,57 @@ async function toggle_enabled() update_icon(enabled); } -async function init_icon() +async function fixicon() { - browser.browserAction.onClicked.addListener(toggle_enabled); let enabled = (await browser.storage.local.get("enabled")).enabled; if(enabled == undefined) enabled = false; update_icon(enabled); } +async function init_icon() +{ + browser.browserAction.onClicked.addListener(toggle_enabled); + fixicon(); +} + init_icon(); +function tryopenwindow(info, tab) +{ + try + { + browser.windows.create({ + url:browser.extension.getURL("reader.html"), + type:"popup" + }); + } + catch(err) + { + console.log(err); + console.log(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } +} +browser.contextMenus.create({ + id: "nazeka-reopen", + title: "Open Reader", + contexts: ["browser_action"], + onclick: tryopenwindow +}); +browser.runtime.onMessage.addListener((req, sender, sendResponse) => +{ + if (req.type == "search") + { + sendResponse(lookup_indirect(req.text, req.time)); + } + else if (req.type == "toggle") + { + toggle_enabled(); + } + else + { + return; + } +}); diff --git a/manifest.json b/manifest.json index fa505fb..e52e7aa 100644 --- a/manifest.json +++ b/manifest.json @@ -5,7 +5,9 @@ "permissions": [ "contextMenus", - "storage" + "storage", + "tabs", + "clipboardRead" ], "background": { @@ -13,7 +15,9 @@ }, "web_accessible_resources": [ - "dict/JMdict.json" + "dict/JMdict.json", + "reader.js", + "reader.html" ], "content_scripts": [ diff --git a/options.html b/options.html index d916e04..6364bae 100644 --- a/options.html +++ b/options.html @@ -12,7 +12,9 @@
- + + +
diff --git a/options.js b/options.js index 8928b8b..b43a7eb 100644 --- a/options.js +++ b/options.js @@ -3,12 +3,16 @@ function restoreListeners() document.querySelector("#enabled").addEventListener("change", setOptions); document.querySelector("#compact").addEventListener("change", setOptions); document.querySelector("#length").addEventListener("change", setOptions); + document.querySelector("#fixedwidth").addEventListener("change", setOptions); + document.querySelector("#fixedwidthpositioning").addEventListener("change", setOptions); } function removeListeners() { document.querySelector("#enabled").removeEventListener("change", setOptions); document.querySelector("#compact").removeEventListener("change", setOptions); document.querySelector("#length").removeEventListener("change", setOptions); + document.querySelector("#fixedwidth").removeEventListener("change", setOptions); + document.querySelector("#fixedwidthpositioning").removeEventListener("change", setOptions); } async function restoreOptions() @@ -24,10 +28,18 @@ async function restoreOptions() let length = (await browser.storage.local.get("length")).length; if(length == undefined) length = 25; + let fixedwidth = (await browser.storage.local.get("fixedwidth")).fixedwidth; + if(fixedwidth == undefined) + fixedwidth = false; + let fixedwidthpositioning = (await browser.storage.local.get("fixedwidthpositioning")).fixedwidthpositioning; + if(fixedwidthpositioning == undefined) + fixedwidthpositioning = false; removeListeners(); document.querySelector("#enabled").checked = enabled?true:false; document.querySelector("#compact").checked = compact?true:false; document.querySelector("#length").value = length?length:25; + document.querySelector("#fixedwidth").checked = fixedwidth?true:false; + document.querySelector("#fixedwidthpositioning").checked = fixedwidthpositioning?true:false; } catch (error){} removeListeners(); @@ -44,6 +56,8 @@ function setOptions() enabled: document.querySelector("#enabled").checked, compact: document.querySelector("#compact").checked, length: length, + fixedwidth: document.querySelector("#fixedwidth").checked, + fixedwidthpositioning: document.querySelector("#fixedwidthpositioning").checked, }); } diff --git a/reader.html b/reader.html new file mode 100644 index 0000000..59df1d2 --- /dev/null +++ b/reader.html @@ -0,0 +1,26 @@ + + +Text Grabber + + + + + +

This page grabs from the clipboard automatically if it contains Japanese text. If this page is not opened, Nazeka will never access the clipboard.

+

Use the context menu (right click the page) to toggle Nazeka.

+
+ + + diff --git a/reader.js b/reader.js new file mode 100644 index 0000000..da45b07 --- /dev/null +++ b/reader.js @@ -0,0 +1,74 @@ +function toggle() +{ + browser.runtime.sendMessage({type:"toggle"}); +} + +browser.contextMenus.create({ + id: "nazeka-toggle", + title: "Toggle Nazeka", + contexts: ["all"], + onclick: toggle +}); + +function might_have_japanese(text) +{ + for(let char of text) + if(char && char.length > 0 && char.codePointAt(0) > 0x2E80) + return true; + return false; +} + +function update(text) +{ + if(!might_have_japanese(text)) + return; + + let target = document.body; + let newnode = document.createElement("p"); + newnode.textContent = text; + + target.insertBefore(newnode, document.querySelector("#helptext")); +} + +let text_previous = ""; +function cycle_text(text) +{ + if(text != "" && text != text_previous) + update(text); + text_previous = text; +} + +window.addEventListener("load", () => +{ + document.querySelector("#nazeka-paste-target").addEventListener("paste", (event) => + { + // skip event if there's no plaintext; thanks github.com/kmltml/clipboard-inserter + let text = event.clipboardData.getData("text/plain"); + if(text !== "") + cycle_text(text); + + event.preventDefault(); + }) +}); + +function checkpaste() +{ + let target = document.querySelector("#nazeka-paste-target"); + + target.parentNode.style.visibility = "visible"; + + target.textContent = ""; + target.focus(); + document.execCommand("paste"); + + target.parentNode.style.visibility = "hidden"; +} + +let interval = 250; + +setInterval(checkpaste, interval); + +var executing = browser.tabs.executeScript({ + file: "/texthook.js", + allFrames: true +}); diff --git a/texthook.js b/texthook.js index 858fa23..92bf39d 100644 --- a/texthook.js +++ b/texthook.js @@ -26,6 +26,8 @@ let settings = { enabled: false, compact: true, length: 25, +fixedwidth: false, +fixedwidthpositioning: false, }; let last_time_display = Date.now(); @@ -45,6 +47,9 @@ function delete_div () function display_div (middle, x, y, time) { + middle.style = "background-color: #111; border-radius: 2.5px; border: 1px solid #111;"; + middle.firstChild.style = "border: 1px solid white; border-radius: 2px; padding: 2px; background-color: #111; color: #CCC; font-family: Arial, sans-serif; font-size: 13px; text-align: left;"; + let find_root = window; let newx = x; let newy = y; @@ -59,32 +64,49 @@ function display_div (middle, x, y, time) } let mydoc = find_root.document; - middle.style = "background-color: #111; border-radius: 2.5px; border: 1px solid #111;"; - middle.firstChild.style = "border: 1px solid white; border-radius: 2px; padding: 2px; background-color: #111; color: #CCC; font-family: Arial, sans-serif; font-size: 13px; text-align: left;"; + let styletext = ""; + if(settings.fixedwidth) + styletext += "width: 600px; " + else + styletext += "max-width: 600px; " + styletext += "position: absolute; top: 0; left: 0;"; + styletext += "background-color: white; border-radius: 3px; border: 1px solid white; z-index: 100000;"; let other = mydoc.body.getElementsByClassName(div_class); + let outer = undefined; if(other.length > 0) { - other[0].replaceChild(middle, other[0].firstChild); - - let styletext = "max-width: 600px; position: absolute; top: " + (newy+5) + "px; left: " + (newx+5) + "px;"; - styletext += "background-color: white; border-radius: 3px; border: 1px solid white; z-index: 100000;"; - other[0].style = styletext; - - other[0].style.visibility = "visible"; + outer = other[0]; + outer.replaceChild(middle, other[0].firstChild); + outer.style.visibility = "visible"; } else { - let outer = mydoc.createElement("div"); + outer = mydoc.createElement("div"); outer.className = div_class; - let styletext = "max-width: 600px; position: absolute; top: " + (newy+5) + "px; left: " + (newx+5) + "px;"; - styletext += "background-color: white; border-radius: 3px; border: 1px solid white; z-index: 100000;"; - outer.style = styletext; - outer.appendChild(middle); - mydoc.body.appendChild(outer); } + + outer.style = styletext; + + + let mywidth = 600; + if(!settings.fixedwidthpositioning) + mywidth = outer.offsetWidth; + + let buffer = 25; + let pretend_doc_width = Math.max(mywidth, mydoc.defaultView.innerWidth); + if(newx + mywidth > pretend_doc_width) + { + newx -= (newx + mywidth - pretend_doc_width); + newx -= buffer; + if(newx < 0) + newx = 0; + } + + outer.style.top = (newy+5)+"px"; + outer.style.left = (newx+5)+"px"; } function exists_div() @@ -455,7 +477,13 @@ async function settings_reload() settings.length = (await browser.storage.local.get("length")).length; if(!settings.length) settings.length = 25; - + settings.fixedwidth = (await browser.storage.local.get("fixedwidth")).fixedwidth; + if(!settings.fixedwidth) + settings.fixedwidth = false; + settings.fixedwidthpositioning = (await browser.storage.local.get("fixedwidthpositioning")).fixedwidthpositioning; + if(!settings.fixedwidthpositioning) + settings.fixedwidthpositioning = false; + if(!settings.enabled && exists_div()) delete_div(); //console.log("set settings"); @@ -464,7 +492,7 @@ async function settings_reload() } catch(error) { - console.log("failed to set settings, maybe not stored yet?"); + //console.log("failed to set settings, maybe not stored yet?"); } // not stored yet, probably settings_reloader = setTimeout(settings_reload, settings_reload_rate);