That said, here is my proposed approach:
Control flow:
- A content script is injected into each page matching some criteria.
- Once injected, the content scripts send a message to the event page (non-persistent background page) and the event page attaches a page=action to the tab.
- As soon as the page-action popup is loaded, it sends a message to the content script, asking for the info it needs.
- The content script processes the request, and responds so the page-action popup can display the info.
Directory structure:
root-directory/
|_____img
|_____icon19.png
|_____icon38.png
|_____manifest.json
|_____background.js
|_____content.js
|_____popup.js
|_____popup.html
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"offline_enabled": true,
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["*://*.stackoverflow.com/*"],
"js": ["content.js"],
"run_at": "document_idle",
"all_frames": false
}],
"page_action": {
"default_title": "Test Extension",
//"default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
//},
"default_popup": "popup.html"
}
// No special permissions required...
//"permissions": []
}
background.js:
chrome.runtime.onMessage.addListener(function (msg, sender) {
// First, validate the message's structure
if ((msg.from === 'content') && (msg.subject === 'showPageAction')) {
// Enable the page-action for the requesting tab
chrome.pageAction.show(sender.tab.id);
}
});
content.js:
// Inform the background page that
// this tab should have a page-action
chrome.runtime.sendMessage({
from: 'content',
subject: 'showPageAction'
});
// Listen for messages from the popup
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
// First, validate the message's structure
if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
// Collect the necessary data
// (For your specific requirements `document.querySelectorAll(...)`
// should be equivalent to jquery's `$(...)`)
var domInfo = {
total: document.querySelectorAll('*').length,
inputs: document.querySelectorAll('input').length,
buttons: document.querySelectorAll('button').length
};
// Directly respond to the sender (popup),
// through the specified callback */
response(domInfo);
}
});
popup.js:
// Update the relevant fields with the new data
function setDOMInfo(info) {
document.getElementById('total').textContent = info.total;
document.getElementById('inputs').textContent = info.inputs;
document.getElementById('buttons').textContent = info.buttons;
}
// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function () {
// ...query for the active tab...
chrome.tabs.query({
active: true,
currentWindow: true
}, function (tabs) {
// ...and send a request for the DOM info...
chrome.tabs.sendMessage(
tabs[0].id,
{from: 'popup', subject: 'DOMInfo'},
// ...also specifying a callback to be called
// from the receiving end (content script)
setDOMInfo);
});
});
popup.html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<h3 style="font-weight:bold; text-align:center;">DOM Info</h3>
<table border="1" cellpadding="3" style="border-collapse:collapse;">
<tr>
<td nowrap>Total number of elements:</td>
<td align="right"><span id="total">N/A</span></td>
</tr>
<tr>
<td nowrap>Number of input elements:</td>
<td align="right"><span id="inputs">N/A</span></td>
</tr>
<tr>
<td nowrap>Number of button elements:</td>
<td align="right"><span id="buttons">N/A</span></td>
</tr>
</table>
</body>
</html>