2017-10-15 173 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

相關問題