16

I'm trying to access some DOM elements from a webpage:

<html>
  <button id="mybutton">click me</button>
</html>

I want to access the innerHTML ("click me") through a chrome extension:

chrome.browserAction.onClicked.addListener(function(tab) {
    var button = document.getElementById("mybutton");
    if(button == null){
        alert("null!");
    }
    else{
        alert("found!");
    }
});

When I click the extension, the popup says: "null". My manifest.json:

{
    "name": "HackExtension",
    "description": "Hack all the things",
    "version": "2.0",
    "permissions": [
    "tabs", "http://*/*"
    ],
    "background": {
    "scripts": ["contentscript.js"],
    "persistent": false
    },
    "browser_action": {
    "scripts": ["contentscript.js"],
    "persistent": false
    },
    "manifest_version": 2
}
TheChosenOne
  • 695
  • 1
  • 6
  • 14
  • 2
    possible duplicate of [Chrome Extension - Get DOM content](http://stackoverflow.com/questions/19758028/chrome-extension-get-dom-content) – Rob W Jan 24 '14 at 20:02

1 Answers1

35

The solution: You need a manifest file, a background script and a content script. This is not really clear in the documentation that you have to use it and also, how to use it. For alerting the full dom, see here. Because I have a hard time finding a complete solution that actually works and not just snippets that are useless for newbies, like me, I included a specific solution:

manifest.json

{
    "manifest_version": 2,
    "name":    "Test Extension",
    "version": "0.0",

    "background": {
        "persistent": false,
        "scripts": ["background.js"]
    },
    "content_scripts": [{
        "matches": ["file:///*"],
        "js":      ["content.js"]
    }],
    "browser_action": {
        "default_title": "Test Extension"
    },

    "permissions": ["activeTab"]
}

content.js

/* Listen for messages */
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
    /* If the received message has the expected format... */
    if (msg.text && (msg.text == "report_back")) {
        /* Call the specified callback, passing 
           the web-pages DOM content as argument */
    sendResponse(document.getElementById("mybutton").innerHTML);
    }
});

background.js

/* Regex-pattern to check URLs against. 
   It matches URLs like: http[s]://[...]stackoverflow.com[...] */
var urlRegex = /^file:\/\/\/:?/;

/* A function creator for callbacks */
function doStuffWithDOM(element) {
    alert("I received the following DOM content:\n" + element);
}

/* When the browser-action button is clicked... */
chrome.browserAction.onClicked.addListener(function(tab) {
    /*...check the URL of the active tab against our pattern and... */
    if (urlRegex.test(tab.url)) {
        /* ...if it matches, send a message specifying a callback too */
        chrome.tabs.sendMessage(tab.id, { text: "report_back" },
                                doStuffWithDOM);
    }
});

index.html

<html>
  <button id="mybutton">click me</button>
</html>

Just save the index.html somewhere and load in the folder as an extension, containing the three other files. Open the index.html and push the extension button. It should show "click me".

TheChosenOne
  • 695
  • 1
  • 6
  • 14
  • To add to this: The content script is the script that can access the web page's DOM. It can pass elements to another script if you need to. The example above uses a background script, but it could be a popup. – Bees Apr 01 '15 at 15:08
  • do you mind explaining the `"matches": ["file:///*"],` line? Isn't this just for local files? – max pleaner Aug 26 '16 at 17:56
  • 1
    It works, but it stop working as soon as I add a `"default_popup": "popup.html"` in "browser_action" (manifest.json) – Elia Weiss Aug 07 '17 at 08:34
  • Is there a way to listen to DOM elements after the extension has been installed? i mean without the onclick event listener?i tried it inside chrome.runtime.onInstalled.addListener but didn't work or i didn't do it correctly. – mr.339 Aug 29 '19 at 08:15