i want to execute a function inside a chrome extension (type: content_page), from the injected javascript inside a webpage loaded at a tab.
How can I do?
if you mean 'injected' as part of the extension then take a look at the developer documentation for message passing.
if the injected is part of the webpage itself, or another non-extension javascript file, i don't believe there is anyway to accomplish this, or any reason it would even be safe.
if it is a function that resides at the global level, just call it as you would any other function (watch out for collisions though; if it is a common name).
Related
We have a Firefox/Chrome web extension which contains both background and content scripts. The background script maintains a cache of shared key/value pairs which are needed by the content scripts. It is not difficult to access them via the browser.runtime.SendMessage functionality.
However, we need access to these key/value pairs as quickly as possible on page load, before any scripts run on the original page. This is generally not possible because the async nature of SendMessage means that the background script will not respond to requests made by the content scripts fast enough.
We've been looking for solutions along the following lines:
1. Sync/blocking lookup
It doesn't appear that there are any mechanisms for this.
2. Initializing the content script
We can register content scripts using browser.contentScripts.register and potentially pass a copy of the entire cache in via javascript. However, this is called only once and all subsequent tabs/pages will load whatever was specified in it. We might be able - with great difficulty - create a listener for global cache changes and re-register a new content script each time.
Are there any better approaches than this?
Update: By adding a listener to browser.webNavigation.onBeforeNavigate, I am now able to inject a global variable which displays in the console output:
In background.js:
browser.webNavigation.onBeforeNavigate.addListener(function(details) {
browser.tabs.executeScript(
details.tabId,
{
code: `window.scope.somevariable=true;
console.log("I executed in content script:", "somevariable", window.scope.somevariable);`
}
);
});
In my library which was injected by register, I am also able to print window.scope out to the console and I see the variable there.
However... when I try to access the variable programmatically, it returns "undefined".
In content script:
// this displays "somevariable" among the window scope properties:
console.log("window.scope", window.scope);
// this displays "undefined":
console.log("somevariable", window.scope.somevariable);
Why can the registered js library output the variable to the console window but can't actually read it?
I am running Xpages in XPiNC.
My usual pattern for an Xpages app is to have a xpHome.xsp page that is set to be the first page that is opened. In this I page I set any scope variables that are at the application level, then head to the "real" first page.
Now I have run into a problem. My current database will send out emails when a status changes, and this will include a doc link to the document, which points to the correct Xpage to open. However, because the user is not going through the home page, then my applicationScope vars are being set.
I thought I could fix this by setting a semaphore in the initApp function - the last thing it would do is to place a "Y" in an applicationScope.semaphore field. So when I open my Xpage the first thing it does is check for that, and if it is null, then I call the initApp function.
For some reason this is not working. But even so I would like to find the equivalent of the old database script "Initialize" event. Something I can call whenever the db is opened for the first time.
How do others handle this problem?
Create a managed Java bean "app" which
works on application scope
sets all application parameters
offers all application parameters
Access the bean with app.xxx in EL or Javascript or call methods directly like app.getXxx() or app.doWhatEverYouWant() in JavaScript.
The bean "app" gets initalized automatically when one of the methods gets called first time.
You can find an example here for start or google for "XPages managed beans" for more Information.
Yes, you have to switch your current code partly to Java but it should be worth it in the long run.
If you want to or have to stay with JavaScript then initialize your application scope variables in a custom control which is included in every XPage like layout.xsp in beforePageLoad event.
Use an additional variable applicationScope.initialized. Check if applicationScope variables aren't initialized yet in JavaScript with
if (!applicationScope.initialized) {
... initialize your applicationScope variables ...
applicationScope.initialized = "yes";
}
I have been going around in circles with this, so I would appreciate some help
This is what I want to achieve
User presses my extension ison
Popup appears with two buttons, 'run function a' and 'run function b'
When they press a button it runs the function in my own js file, that I have injected.
Function a for example, could be to count the number of elements of a certain type in the active tab
So, I can inject my js file on page load (this is in my contentscript.js)
var s = document.createElement('script');
s.src = chrome.extension.getURL('temp-file.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
This works, and I can see the js being excuted
But what I can do is to have a function run that is in temp-file.js
For example in the popup I have
chrome.tabs.executeScript(null, {code:"shows();"});
I get this: Uncaught ReferenceError: shows is not defined
If I enter shows(); into the console, it works as expected
I presume that the issue is all about the context. I tried various things in the popup.js page to also inject the file but nothing seemed to work
Is anyone able to point me in the right direction please
Thanks
Grant
I presume that the issue is all about the context.
You're right about it.
The file "temp-file.js" has been injected into host page, so it is now part of host page context. Extension can mess with it - since it is in different context.
Run a function from injected js
Solution:
Not sure about what you are trying to achieve. pick what suits you:
Split injected file
Code/functions you want to execute on a page - use them as contentscript.
In this case split you "temp-file.js" - part extension has execute (becomes part of contentscript) and part host page has to execute(your code snippet).
use custom event
Use custom event - generate custom event in contenscript - listen for it injected script. custom event
Your question does not say what exactly you are trying to achieve.
This is what I understood. You want to execute a function on your contentscript.js from your popup.js.
If that is the case then you can call a method on contentscript from popup.js like mentioned here https://developer.chrome.com/extensions/messaging
My Chrome extension has a background page that execute script on current tab.
The script change elements on current tab by adding code to existing elements to call function 'myFunction' defined at background page when 'onClick' events occur.
The problem is that exception is thrown that 'myFunction' is not defined on current tab.
what is the best way to enable this interaction? to enable current page to go to function defined on background page?
Thanks in advance!
The background page is executed in an independent context, and thus its functions can't be directly executed in the currently opened tab.
What you need is a content script executed on all the tabs, that then communicates with the background page, using the message passing mechanism.
Without more information, it's difficult to help you more.
As mentioned in the first answer, "Without more information, it's difficult to help you more.", but for your second question it sounds like what you need is a reference to the function defined in your background page. This can be achieved with the getBackgroundPage function. The code looks like this;
var bgPage = chrome.extension.getBackgroundPage();
bgPage.myFunction();
In am using YUI browser history manager for keeping track of Ajax navigations. I am registering history object like:
YAHOO.util.History.register("state",init, onStateChange);
Here onStateChange is getting called when I do
YAHOO.util.History.navigate("state",urlhash);
and when I press back button.
Is there any way to know if onStateChange is called on back button or by calling navigate?
If this event can be called by an external system sometimes (in this case the browser back button) and by your own code sometimes, you can differentiate the caller by making it a requirement to do something special when your own code calls the method. Wrapping the call to navigate() in your own helper method can help make sure you stay consitent with this.
In the YUI docs I see that register() can take an optional 4th parameter (among others) which is an arbitrary object that will get passed into your onStateChange handler function. One of the properties of this object could be a flag indicating that it was called from your code versus initiated by the browser, and in your navigate() wrapper always set that flag. Remember to set it back in your handler.
Note: I am not as familiar with YUI as ExtJS, maybe some guru that knows the API better can help, but this is a general strategy that can work. This answer makes an inelegant assumption that a call to navigate() will make that handler fire reliably before any other navigation has a chance to occur, which is probably a safe bet in the single-threaded javascript world.