如何从活动标签中获取后台脚本中的选定文本(热键后)?
我试图像例如按Ctrl + SHIFT +数一个后热键来获得从网页选定的文本。我从Firefox帮助中的代码开始。如何从活动标签中获取后台脚本中的选定文本(热键后)?
在manifest.json:
{
"description": "Native messaging example extension",
"manifest_version": 2,
"name": "Native messaging example",
"version": "1.0",
"icons": {
"48": "icons/message.svg"
},
"applications": {
"gecko": {
"id": "[email protected]",
"strict_min_version": "50.0"
}
},
"background": {
"scripts": ["background.js"]
},
"commands": {
"toggle-feature": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"linux": "Ctrl+Shift+0"
},
"description": "Send a 'toggle-feature' event"
}
},
"browser_action": {
"default_icon": "icons/message.svg"
},
"permissions": ["nativeMessaging"]
}
的JavaScript文件:
/*
On startup, connect to the "ping_pong" app.
*/
var port = browser.runtime.connectNative("ping_pong");
/*
Listen for messages from the app.
*/
port.onMessage.addListener((response) => {
console.log("Received: " + response);
});
/*
On a click on the browser action, send the app a message.
*/
browser.browserAction.onClicked.addListener(() => {
console.log("Sending: ping");
port.postMessage("ping");
});
browser.commands.onCommand.addListener(function(command) {
if (command == "toggle-feature") {
console.log("toggling the feature!");
text1 = window.getSelection();
console.log(text1);
}
});
调试器说:
选择{anchorNode:空,anchorOffset:0,focusNode:空, focusOffset:0,isCollapsed:true,rangeCount:0,caretBidiLevel:null }
消息传递作品,热键作品,但我无法获取选定的文本。我需要使用另一种方法吗?我昨天尝试了很多代码,但我没有找到如何去做。有时我会从调试器中看到另一个错误,但我永远无法获取选定的文本。这是一个焦点问题?这太疯狂了!
我从其他加载项读取代码。看来他们使用这种方法,但也许它是在一个弹出窗口?
我在Debian Stretch和Firefox 56上。我在2台电脑上试过。
要获取选定的文本,您必须使用内容脚本。鉴于您正在启动从用热键定义的热键获取选定文本,您最好使用tabs.executeScript()
在用户按下热键时插入所需的代码。
下适应你的问题有代码做仅是定义热键,并增加了越来越使用注入到在activeTab
所有帧的选择(基于代码Get the Highlighted/Selected text)的部分。
用户可以在每个现有的iframe中进行选择。你需要确定你想如何处理。下面的代码从每个iframe中获取选择。但是,它目前丢弃除最后选择的所有内容(第一个结果是主框架)。您可能希望在多个框架中进行选择时通知用户。请注意,Chrome不允许在多个框架中选择文本,但Firefox可以。
以下代码在Firefox和Chrome中均经过测试。
manifest.json的:
{
"description": "Get selected text upon hotkey",
"manifest_version": 2,
"name": "Hotkey: get selected text",
"version": "1.0",
"icons": {
"48": "icon.png"
},
"background": {
"scripts": ["background.js"]
},
"commands": {
"get-selected-text": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"linux": "Ctrl+Shift+0"
},
"description": "Get the selected text from the active tab."
}
},
"permissions": [
"activeTab"
]
}
background.js:
chrome.commands.onCommand.addListener(function (command) {
if (command == "get-selected-text") {
chrome.tabs.executeScript({
code: '(' + getSelectionText.toString() + ')()',
//We should inject into all frames, because the user could have made their
// selection within any frame, or in multiple frames.
allFrames: true,
matchAboutBlank: true
}, function (results) {
selectedText = results.reduce(function (sum, value) {
//This checks all the results from the different frames to get the one
// which actually had a selection.
if (value) {
if (sum) {
//You will need to decide how you want to handle it when the user
// has things selected in more than one frame. This case is
// definitely possible (easy to demonstrate).
console.log('Selections have been made in multiple frames:');
console.log('Had:', sum, ':: found additional:', value);
}
// Currently, we just discard what was obtained first (which will be
// the main frame). You may want to concatenate the strings, but
// then you need to determine which comes first. Reasonably, that
// means determining where the iframe is located on the page with
// respect to any other selection the user has made. You may want
// to just inform the user that they need to make only one
// selection.
return value;
}
return sum;
}, '');
console.log('selectedText:', selectedText);
})
}
});
//The following code to get the selection is from an answer to "Get the
// Highlighted/Selected text" on Stack Overflow, available at:
// https://*.com/a/5379408
// The answer is copyright 2011-2017 by Tim Down and Makyen. It is
// licensed under CC BY-SA 3.0, available at
// https://creativecommons.org/licenses/by-sa/3.0/
function getSelectionText() {
var text = "";
var activeEl = document.activeElement;
var activeElTagName = activeEl ? activeEl.tagName.toLowerCase() : null;
if (
(activeElTagName == "textarea") || (activeElTagName == "input" &&
/^(?:text|search|password|tel|url)$/i.test(activeEl.type)) &&
(typeof activeEl.selectionStart == "number")
) {
text = activeEl.value.slice(activeEl.selectionStart, activeEl.selectionEnd);
} else if (window.getSelection) {
text = window.getSelection().toString();
}
return text;
}
我找到了一个解决方案:
我选择任何网页上的文字,我有背景中的文字。JS之后,我可以做我想要的文字。在我的具体情况下,我使用外部程序(以python)接收选定的文本。
的manifest.json
{
"description": "Native messaging + Hotkey + content-script messaging",
"manifest_version": 2,
"name": "getSelectedTextFromHotkey",
"version": "1.0",
"icons": {
"48": "icons/message.svg"
},
"applications": {
"gecko": {
"id": "[email protected]",
"strict_min_version": "50.0"
}
},
"background": {
"scripts": ["background.js"]
},
"commands": {
"toggle-feature": {
"suggested_key": {
"default": "Ctrl+Shift+4",
"linux": "Ctrl+Shift+5"
},
"description": "Send the selected text"
}
},
"browser_action": {
"default_icon": "icons/message.svg"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"]
}
],
"permissions": [ "<all_urls>","nativeMessaging","webRequest"]
}
Background.js
var port = browser.runtime.connectNative("gettext");
browser.runtime.onConnect.addListener(connected);
port.onMessage.addListener((response) => {
console.log("Received: " + response);
});
function onExecuted(result) {
console.log(`We executed`);
}
function onError(error) {
console.log(`Error: ${error}`);
}
browser.commands.onCommand.addListener(function(command) {
if (command == "toggle-feature") {
console.log("toggling the feature!");
var executing = browser.tabs.executeScript({ file: "/content-script.js", allFrames: false });
executing.then(onExecuted, onError);
}
});
var portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.onMessage.addListener(function(m) {
console.log("message selected:")
console.log(m);
console.log("Sending: ping");
port.postMessage("ping");
});
}
内容的script.js
//内容的script.js
var selectedText = getSelection().toString();
var myPort = browser.runtime.connect({name:"port-from-cs"});
myPort.postMessage(selectedText);
gettext.json
{
"name": "gettext",
"description": "Native messaging + Hotkey + content-script messaging",
"path": "/home/marie/web-ext/gettext.py",
"type": "stdio",
"allowed_extensions": [ "[email protected]" ]
}
gettext.py
#!/usr/bin/python -u
# Note that running python with the `-u` flag is required on Windows,
# in order to ensure that stdin and stdout are opened in binary, rather
# than text, mode.
import sys, json, struct
# Read a message from stdin and decode it.
def getMessage():
rawLength = sys.stdin.read(4)
if len(rawLength) == 0:
sys.exit(0)
messageLength = struct.unpack('@I', rawLength)[0]
message = sys.stdin.read(messageLength)
return json.loads(message)
# Encode a message for transmission, given its content.
def encodeMessage(messageContent):
encodedContent = json.dumps(messageContent)
encodedLength = struct.pack('@I', len(encodedContent))
return {'length': encodedLength, 'content': encodedContent}
# Send an encoded message to stdout.
def sendMessage(encodedMessage):
sys.stdout.write(encodedMessage['length'])
sys.stdout.write(encodedMessage['content'])
sys.stdout.flush()
# BE CAREFUL, NEVER USE THE CONSOLE in the loop ! it stops the connection!!!
while True:
receivedMessage = getMessage()
if (receivedMessage == "ping"):
sendMessage(encodeMessage("pong"))
它似乎在Firefox上很好地工作。
这比它需要的复杂得多。试试Makyen的答案。 – Smile4ever
我建议你阅读[WebExtension的解剖学](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension)页面(也许通过阅读从那里链接的页面来工作)。它具有整体架构信息,可帮助您了解事物的组织/完成情况。您需要使用[内容脚本](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts)与网页进行交互(例如,操纵DOM,听取页面上的点击,获得当前选择等)。 – Makyen
但是,您要做什么来获得选择(即使您已将代码正确放置在内容脚本中)是不够的,您需要使用此答案中包含的更长,更复杂的代码:[获取高亮显示/ Selected text](https://*.com/a/5379408)。这是代码片段中的getSelectionText(),而不是第一个版本。 – Makyen
没什么作用,我昨天试了这些功能。我现在重试,但同样的错误。我取消了所有加载项。你给我一个内容脚本的链接,但我需要添加这个?我不明白 – ce6999