There are a few questions about this but none met my needs. I have created an extension and I am trying to communicate between a content script and my options.html. I have been trying to use the chrome.extension.onRequest.addListener and the chrome.extension.sendRequest and neither work at all. No commands are executed or anything. Here is my code:
content script:
chrome.extension.sendRequest({command:value}, function(response) {});
options.html
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
alert("in onRequest request.command = " + request.command);
decide_command(trim(request.value));
sendResponse({});
});
none of the alerts are executed and none of the functions are executed. I even tried using the example in the messaging API page and it didn't trigger any alerts or anything. I have tried a bunch of different combinations like putting the extension ID in the sendRequest to make sure its going to the right place, I have excluded the sendResponse to make sure it wasn't ending too quick. I have debug alerts all over and none get triggered except for the ones before and after the send request command in my content script. So I would assume it either gets executed and fails or something like that. Any help would be greatly appreciated I have been working on this for days.
I believe Chris noted an issue already: an extension's option page isn't running all the time, and is therefore not available to receive or generate messages. Background pages are better for this sort of communication, as they're always running, always available, and therefore always capable of responding to messages.
I'd suggest reworking your extension's architecture a bit such that the content script gathers relevant information and sends it to the background page. When the options page is opened, it can request the state from the background page. The background page is then responsible for maintaining state in a reasonable way, and for pushing information back and forth between the other pieces of your extension.
Does that make sense?
Related
I dont really unterstand how the Chrome Extension API works. It was a rough to understand how the background.js and the content.js works, but my current Problem is, that the function insertCSS(); seems to need the tabId, even if the official documentation says that its optional.
So, none of the Answers on this plattform could help me, because I dont even understand the Concept of the whole API.
So can anybody explain me, why something like this is not possible?
var tabInfo = chrome.tabs.getCurrentTab();
var id = tabInfo.tabId;
There are several questions to be answered here.
Literal question
So can anybody explain me, why something like this is not possible?
var tabInfo = chrome.tabs.getCurrentTab();
Short answer: because most of the Chrome API does not return a value; it is asynchronous, meaning that some other component of Chrome will work on getting the answer while JS execution resumes.
A comprehensive overview of JS asynchronicity can be read at this canonical question.
There are two ways to deal with it:
Use callbacks, and be aware that the actual callback execution happens after the rest of the calling code.
Use async/await and/or Promises. The WebExtension polyfill can help with that, but it's outside the scope of the question.
Question in title
Simplest Way to get the current Tab Id?
or "why chrome.tabs.getCurrentTab won't help you".
chrome.tabs.getCurrentTab() returns the tab ID of the calling page. See the docs.
This is of limited utility: only extension pages (and not content scripts) can call this API.
Extension pages are:
background (no tab ID),
popup (no tab ID),
options page (it's complicated as it's embedded in a Chrome page),
"other" extension pages opened in a visible tab (here, it works as expected).
It's not your use case, as established in the comments.
The actual way to get the current active tab is chrome.tabs.query() with the query {active: true, currentWindow: true}, but keep on reading.
Actual question you're having
As reconstructed from the comments, here's the actual scenario you're having:
I have an event in a content script. I need to call the tabs.insertCSS API, so I'm messaging the background page to do it for me. How do I get the tabId for this call?
Well, the key here is to take a closer look at the runtime.onMessage event listener signature:
The callback parameter should be a function that looks like this:
function(any message, MessageSender sender, function sendResponse) {...};
What's a MessageSender?
An object containing information about the script context that sent a message or request.
tabs.Tab (optional) tab
The tabs.Tab which opened the connection, if any. This property will only be present when the connection was opened from a tab (including content scripts), and only if the receiver is an extension, not an app.
[...]
Jackpot. We're sending the message from a content script, and the listener is handed the sender.tab information "for free". We just need a quick detour into tabs API docs to see what a Tab contains, and we have it:
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
chrome.tabs.insertCSS(sender.tab.id, {/*...*/});
});
Misconception
my current Problem is, that the function insertCSS() seems to need the tabId, even if the official documentation says that its optional
It doesn't. If you call it omitting the tabId, which makes the details object the first argument, then Chrome will assume you want the "the active tab of the current window".
It may seem that this doesn't work if you're trying to execute it in the Dev Tools window for the background page. That's because in this instance there's no such tab. The current window is the one you're putting the console command in. So what the call does without the tabId is very sensitive to what actually is the current window.
It may also be the case that you don't have the permissions to inject in the current active tab, that would also fail.
Generally, it pays to be specific with the tab ID, it removes uncertainty about the logic of the extension.
To be specific, (although I am also interested in a general solution, if anyone would care to explain) I am trying to "click" Steam's 'Not Interested' button.
I have the urls of the pages I want to do this on in a Python script, alternatively I can write them in a file somewhere.
As much as I (think I) know about that button, it has no ID, and the relevant bit of code that is executed is:
$J.post('http://store.steampowered.com/recommended/ignorerecommendation/', {
sessionid: g_sessionID,
appid: store_appid
})
I am mostly unfamiliar with Javascript, but copying the headers and parameters, I managed to successfully send that post request (in Python instead), which worked. The problem with that is that it seems it requires the following cookies: steamRememberLogin, steamLogin, sessionid. I am rather sure those won't forever stay the same, and so my script would soon break.
I am unsure what to do from here on. I could imagine somehow automatically getting those cookies from somewhere, but where and how? Alternatively if something could actually send a click event from the button, I think that might be possible in Javascript?
And if this bit's important, then it doesn't need to operate in the background. As long as it can be scheduled, it's fine if it needs to actually open up that webpage in my browser.
I am trying to load the HTML content of a webpage outside of my domain, which I can do just fine using functionality provided by this jQuery plugin: http://www.ajax-cross-origin.com/. However, when I print out the HTML there are pieces missing, which I assume is because the ajax request gets the HTML before the page is fully loaded. When I say "pieces missing," I mean that some tags that should have innerHTML in fact have none. Here's my code:
$.ajax({
crossOrigin: true,
url: "http://siriusxm.com/bpm",
success: function(data) {
console.log(data);
},
timeout: 5000
});
The crossOrigin attribute is from the plugin I mentioned. I get the same behavior with and without the timeout (and strangely, it doesn't seem as though the timeout is doing anything at all--when I check the console, it logs data pretty much immediately).
Is there a way to wait until the page is fully loaded before getting the content? For what it's worth, this is all part of a chrome extension I'm developing, so if there's anything else code-wise you might need just ask.
Thanks!
So according to your comments, the information you're looking for is just the Now Playing artist and Song, which you won't be able to get by loading just the source of the main page.
To find the data you're looking for just open up your Chrome DevTools, go to the network tab, and Refresh to see all requests on the page.
It looks like this is the request you want, you just need to update the timestamp every minute:
http://www.siriusxm.com/metadata/pdt/en-us/json/channels/thebeat/timestamp/08-12-03:48:00
Just parse that json and grab what you need. Of course they can always change the location or format of the file, but for right now that's what it is.
If the console log is showing all of the data you're looking for then the ajax call should be fine.
Any code in the success callback will be ran after the ajax call, so just use JQuery in the success callback function to insert data into the html. All I see there now is the console.log(data) unless you've removed some code.
The timeout just gives the ajax call a set amount of time to complete before it "times out", in other words it tells it to stop waiting after the set amount of time.
Some users repeatedly run into a very mysterious problem when using my web application.
In the middle of using it, they'll click a button or link that takes them to another page, but there will be a "page not found" error, because the URL is something like:
http://www.correctwebsitename.com/undefined
I thought it might be a javascript bug in my app: a redirect done by choosing a page name (maybe with some parameters) where one of the values is bad, resulting in the page name = "undefined". But there is no such code in my app anywhere, and this happens on many different pages, seemingly at random.
The one thing that seems to make it happen more often is if the user logged in originally by clicking a link in an email message in gmail. But a user who cut and pasted the link URL into a browser window said it still happened. Googling around reveals some hints that some kind of Google redirecting or caching is happening behind the scenes.
Any ideas?
Edit:
I'm not getting responses from anyone familiar with how gmail links etc work, does anyone know what SO tags google experts "hang around in"?
Edit 2:
Awarding bounty to top answer for useful info and temporary workaround idea, but still interested in real solution to the problem, so not accepting workaround as solution.
I believe you are right about gmail doing something with the links. See the gmail image below:
Non-standard header fields are conventionally marked by prefixing the field name with X-
Its probably behaving like... oh well, Google, and inspecting everything.
To stop google search from tracking my clicks i had to create a userscript to rewrite one of their functions:
rwt = function(){};
Maybe you can try something similar for gmail.
What is rwt?
rwt() is a javascript function from google search that rewrites the links to track which site you have visited.
for example, searching for "greasemonkey" showed the mozilla addons page as the first result. clicking on it opened
https://www.google.com.br/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCUQFjAA&url=https%3A%2F%2Faddons.mozilla.org%2Fpt-BR%2Ffirefox%2Faddon%2Fgreasemonkey%2F&ei=iWNtUIXjIoyQ8wTxv4DQAQ&usg=AFQjCNEO9EJcHp9rAmKyD_XZF2Bt6hs_YQ&sig2=P19xVUsD-Q1G_9AiUBP3PQ
and then redirected to
https://addons.mozilla.org/pt-BR/firefox/addon/greasemonkey/
The image above and the rwt() case is just to show you that there is a great chance that gmail is changing the links, so this could be related to your problem.
Since there is nothing you can do at gmail's side, maybe you could fix it on your server, by redirecting http://www.correctwebsitename.com/undefined to http://www.correctwebsitename.com or any other page that you'd like your users to see.
So, be it from gmail or any other referer, every time a client lands on http://www.correctwebsitename.com/undefined redirect him to another page.
so maybe I can figure out how to just send them back to the page they
came from
ASP
if not request.UrlReferrer is nothing then
response.redirect (request.UrlReferrer.tostring)
end if
JS (for this to work, you would have to actually create a page called undefined)
if (window.location.href.toLowerCase().indexOf('undefined') > -1) {
// this works
window.location.href = document.referrer;
// this works too (uncomment to enable)
// history.back();
}
remember that if the user directly typed the url or used the link from favorites there wont be no referrer
I would suggest you to check the below things in your application.
Is there any code in your application, apart from what you own ?
there can be injected code by third party applications, like for ex "AddThis" adds an extra #parameter to your url sometimes, in your case its clear that a javascript is trying to playaround with the location.href as "undefined" is something which many js developers will come across.
by adding an # will help do cross site communication, some bug might also be causing an issue here.
Do a complete search in your code for "location.href" and see if you have used it anywhere.
Sometimes third party addons on the browser too might cause this issue
hope these would help you narrow down to your problem.
if you are not able to trace out the issue anywhere, i would suggest you to override 404 functionality on your webserver and implement the solution using Referrer.
I want to read the contents of Gmail messages and add some fancyness on links. Here's some code:
unsafeWindow.gmonkey.load("1.0", function(gmail){
gmail.registerViewChangeCallback(function(){
if (gmail.getActiveViewType && gmail.getActiveViewType() == "cv") {
var viewElement = gmail.getActiveViewElement()
// Do things with viewElement
}
})
})
The actual detection of links in the dom objects for the mails is the easy part. The problem is that the registerViewChangeCallback only runs when you display a thread. Large threads will have most of it's messages hidden, only to be loaded by a users request. I haven't found a Gmail greasemonkey API method for this particular action (loading a individual message), which is when I need to run my script.
Any suggestions?
As you say, the registerViewChangeCallback() function only fires when the user changes their view from e.g. threads to archives, etc.
What you really need is to add a function that intercepts gmail's post-backs and then changes the links. I have never tried doing it myself, but this answer has some sample code for you. When gmail has retrieved a new message, it will fire a readystatechange event, which your code can intercept. You can then change the contents of the message in whichever way you wish (although you may have to wait for a moment to allow gmail to insert the message first - not sure about that one).
I think you'll find that some messages are loaded when they're listed in the thread; hence your problem.
Why don't you just use a custom style anyway? UserStyles FF plugin.