2017-10-15 176 views
2

我试图像例如按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台电脑上试过。

+0

我建议你阅读[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

+0

但是,您要做什么来获得选择(即使您已将代码正确放置在内容脚本中)是不够的,您需要使用此答案中包含的更长,更复杂的代码:[获取高亮显示/ Selected text](https://stackoverflow.com/a/5379408)。这是代码片段中的getSelectionText(),而不是第一个版本。 – Makyen

+0

没什么作用,我昨天试了这些功能。我现在重试,但同样的错误。我取消了所有加载项。你给我一个内容脚本的链接,但我需要添加这个?我不明白 – ce6999

回答

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://stackoverflow.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; 
} 
0

我找到了一个解决方案:

我选择任何网页上的文字,我有背景中的文字。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上很好地工作。

+0

这比它需要的复杂得多。试试Makyen的答案。 – Smile4ever

相关问题