It seeems that my content script document.URL always has the same value even when I click on a random <a href link.
In the below function in the content script, I have a function called performclick() which finds a random link on the current document, then clicks it.
Now shouldn't the next time I call performclick(), I get another document object? i.e. document of the currently focused active tab?
Like when I click a link on the main page and it opens a new tab with another website loaded in it, then I need the content script to give me the document of this new tab that has the clicked website link loaded in it.
But some how I always keep getting the document object of the same main page.
Please help
Manifest
{
"manifest_version": 2,
"name": "OSP Updater",
"version": "1.0.0",
"content_scripts": [{
"run_at": "document_start",
"js": ["content.js"],
"matches": [ "<all_urls>" ]
}],
"permissions": [
"background", "webRequest", "webRequestBlocking", "tabs", "<all_urls>"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"web_accessible_resources": ["jsui.js"]
}
Content Script
window.onload = function () {
var elm = document.getElementById("my-container");
if (elm != undefined && elm != null) {
//alert("Main Page LOADED!!!");
}
}
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.clickit == "yes") {
performclick();
}
});
function performclick() {
//document.URL is always the same
var links = document.querySelectorAll("a");
if (links.length) {
var linkToClick = links[1];
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent('click', true, true);
linkToClick.dispatchEvent(clickEvent);
}
}
Update #1:
Silly me, it turns out that I was sending a message from my background script to my content script via the first tab.
I did my clicking decision in the background script than sends a signal to the content script so that the content script can do the actual clicking.
So since I was sending message from the background script to the content script in the 1st tab, it lead the document object to always belong to the first tab (i.e. main page).
Hope this helps someone, always check if you are doing messaging then check its logic.
Related
Although there are a lot of similar questions here, I couldn't solve my problem with any of the accepted solutions, so I'm creating a new question.
I have a content script that adds some functionality to a Jira Issue.
However, when navigating to the Jira Issue from a Filter Results Page, the content script doesn't run until I manually reload the page.
What I've tried so far:
Adding webNavigation Listeners (with the manifest permission), but none of them seem to trigger when the Jira Issue link is clicked from the Filter Page.
// background.js
const myLog = () => console.log('webNavigation event triggered');
browser.webNavigation.onDOMContentLoaded.addListener(myLog);
browser.webNavigation.onHistoryStateUpdated.addListener(myLog);
browser.webNavigation.onReferenceFragmentUpdated.addListener(myLog);
Adding "all_frames": true to the manifest.json, but that didn't make it work either:
// manifest.json
...
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["*://jira.atlassian.com/*"],
"js": ["content.js"],
"all_frames": true
}
],
"permissions": ["tabs", "webNavigation", "<all_urls>"]
Listening to window.onpopstate event inside the content script. Although it detects when I click the "Back" and "Forward" arrows in the browser, it doesn't fire when I click the links inside the Filter Results Page.
// content.js
window.onpopstate = () => {
browser.runtime.sendMessage('webNavigation event triggered');
}
How can I run this content script without having to manually reload the page?
In console I can input document.getElementById('...') and get a value back. Or even .textContent and get the string I want.
Once I pop this into my chrome extension and run it, it evaluates document.getElementById('...') as null. What's up?
Manifest.json:
{
"name": "CSUF RMP",
"version": "0.1",
"manifest_version" : 2,
"description": "Displays professor ratings on icon click",
"background" : {
"scripts" : ["background.js"]
},
"browser_action": {
"default_icon": "icon16.png"
},
"content_scripts": [
{
"matches": ["https://mycsuf.fullerton.edu/*"],
"js": ["script.js"]
}
],
"permissions": ["<all_urls>", "*://*/*", "http://*/*", "https://*/*"]
}
Background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "script.js"});
});
My script.js is literally what I posted at the top. The script is supposed to have access to the web page's DOM (thus I need a content script) and run it on click of the icon (hence the background.js)
I can get the page to run and show an alert or something, but that line isn't evaluating the page's dom, just null.
I think I know what is the problem here,
you are executing script.js just like a normal script, and a normal script can't interact with the page DOM, you can think about it as just runing a script from a file- it don't have the content script's privileges that way.
What you can do is open a new tab (with the url of the content script), and then pass to the content script at that new tab a message which tells him to run a specific function there.
You can test it without using message sending by setting the onload of the content script to something like: onload=alert(document.getElementById('...')); and than open a new tab from the background page: chrome.tabs.create({"url":"https://mycsuf.fullerton.edu"});
tell me how it goes :)
Edit: forgot to mention that you need the 'tabs' permission in your manifest file in order to open new tabs and test the thing out.
My Chrome extension has a Content-Script that injects a custom DIV into the current page. This part works.
But then, the extension also has a right-click Context Menu, which when clicked, should modify this injected DIV in some way (let's say, add some text into that DIV). The issue is that the injected content isn't found. The right-click menu handler is in Background.js, and this file doesn't know anything about the content.
manifest.js
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"css": ["contentstyle.css"],
"js": ["jquery-1.11.2.min.js", "contentscript.js"],
"background": {
"persistent": true,
"scripts": ["background.js"]
},
contentscript.js
// Add Custom DIV - works OK
var div = document.createElement( 'div' );
div.id = 'infoDiv';
document.body.appendChild( div );
document.getElementById('infoDiv').innerHTML = 'TEST';
background.js
// Add menu - gets added, but can't see Injected Content from here
chrome.contextMenus.create({
"title": "My Right-Click Menu",
"contexts": ["image"],
"onclick" : changeDiv
});
function changeDiv(e)
{
var divHTML = document.getElementById('infoDiv').innerHTML;
alert('Current HTML in DIV: ' + divHTML);
}
I'm unable to get the divHTML from the Background script, there is some kind of error and no alert box. Can there be communication between the Background and Content? I'm forced to implement menus in the Background script, right?
Wrong document in
var divHTML = document.getElementById('infoDiv').innerHTML;
Please read the Architecture Overview first. Your background script is executed in a separate HTML document, and as such won't "see" the page in the tab.
You'll need to pass the value to the content script to do something with a visible page. You'll probably need Messaging.
So, I understand that you cannot have background scripts and a default popup together. If this is so, how can I have something similar to a default popup (where there is some simple HTML that appears when you clicked the extension's icon) and have the background script modify the contents of that popup?
Here's the manifest.json
"browser_action": {
"default_title": "Mark this position!",
"default_icon": "icon.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": ["content.js"]
}
],
You absolutely can have both a popup (i.e. default_popup set) and a background page. The background page will have its own lifecycle (with "persistent": false it's an Event page) and the popup will exist as long as it's open.
I guess your confusion stems from the fact that you cannot have a popup and a chrome.browserAction.onClicked listener at the same time.
This is true, but there are other ways to tell your background page that the popup has opened.
You can message the background page from the popup:
// popup.js, should be included in the popup
chrome.runtime.sendMessage({popupOpen: true}, function(response) {
/* process response */
});
// background.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.popupOpen) {
/* do stuff */
sendResponse(response);
}
});
If you put the above popup code on the top level, then the background will be informed as soon as the popup opens.
While you can directly access the popup's window from the background (see chrome.extension.getViews), it's recommended that you move the UI logic into the popup itself and communicate with the background using Messaging as above and shared chrome.storage.
I'm trying to stop all tabs from loading when chrome starts up. I then
want to load only the tab I click on.
I was able to do this by using a content script in
manifest.json.
{
"name": "blah",
"version": "1.0",
"background_page": "background.html",
"content_scripts": [
{
"matches": ["http:// */*"],
"js": ["stop.js"],
"run_at": "document_start"
}
] ,
"permissions": [
"tabs", "http://*/*"
]
}
stop.js just contains one line
window.stop();
Now this isn't ideal because, being a content script it stops loading
everytime, including when I click on a tab.
So, I tried doing in in background.html without a content script, but
I can't get it to work:
background.html
<!doctype html>
<html>
<script>
chrome.tabs.getAllInWindow(null, function stopTabs(tabs) {
for (var i in tabs) {
var tab = tabs[i];
//alert(tab.url);
var stopLoading = {'code': 'window.stop();alert("stopped");'}; //alerts work here, but window.stop doesn't?!!
chrome.tabs.executeScript(tab.id, stopLoading);
}
});
</script>
</html>
How do I do this? Loading the clicked tab seems easy, but I need to do this first.
Looks like this problem is related to this bug report, if you star it maybe it will get fixed sooner.