Chrome extensions: is it possible to call a function in the options page from the background page? - google-chrome-extension

How do I call a function in the options page from the background page?
For example, in the options page, you can call:
chrome.extension.getBackgroundPage().updateIcon("someDifferentIcon.png");
thereby communicating with the background page from the options page. How do you communicate with the options page from the background page?
One possible difficulty is that the options page is not always open (unlike the background), so that may explain why its not built-in (like above). My question is, is it possible to do?

A simple approach to implement your idea is using "chrome.extension.sendRequest" API. For example:
options.js:
chrome.extension.sendRequest({id:"updateIcon", filename:"foo.png"});
background.js:
chrome.extension.onRequest.addListener(funciton(request) {
if (request && (request.id == "updateIcon"))
updateIcon(chrome.extension.geURL(request.filename));
});

If the options page is already open, you can use chrome.extension.getViews({type:"tab"}) to get a hold of its window object and then call functions on it (you'll need to iterate over the returned views and pick the one with the URL that is the URL of your options page). If it's not open yet, you can use the tabs API to open a tab that points to it first, and then use chrome.extension.getViews.

Related

Trigger a dialog box in background script

I have a chrome extension, where I periodically throw out an alert based on something.
The thing is that the default alert in Javascript is very ugly and I am trying to replace it with something more beautiful.
The problem is that currently the alert is triggered from the background script. Google doesn't allow us to include any external libraries in the background html.
Given this problem, how do I go about replacing the default alert with a more modern UI alert?
I was looking to replace the default alert with something like the SweetAlert.
My background.js currently looks like this:
// on some alarm trigger
function showpopup() {
console.log(" in show popuup");
console.log(Date());
alert("ugly alert");
}
I also explored the option of injecting another js file from my background file.
function showpopup() {
console.log(" in show popuup");
console.log(Date());
var s = document.createElement('script');
// added "script.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
}
My script.js currently just calls an alert
alert("ugly alert now in script.js");
I am not able to figure out how to create my own dialog box in this javascript file script.js.
The problem is where your alert will be shown?
In an browser/OS dialog window? That's what alert() and friends do; as you see yourself, it's ugly and inflexible. In addition, it's technically challenging: it's an old mechanism that stops execution of JS code until closed, which can lead to API malfunctioning; Firefox WebExtensions specifically don't support calling this from the background page.
In the background page? By definition, it's invisible. You can add DOM nodes with an alert there, but you will not see it. Your problem isn't loading a library, your problem is where to display results.
(invisible, so no picture here!)
In the currently open tab? Hijacking an arbitrary page to show your own UI is hard, prone to break, would require draconian permissions with user warnings at install, won't always work. Wouldn't recommend.
In a fresh window? Possible (see chrome.windows API), but hardly "modern UI" at all (at least you can hide the URL bar).
In a browser action popup? Still not possible to trigger it to open in Chrome, so that's out.
The de-facto standard for informing the user about such things is the chrome.notifications API. It offers limited customization, but that's the "modern" approach considering that your extension has no UI surfaces already open at alert time.
You can insert your code into the tab content via
JS: chrome.tabs.executeScript()
CSS: chrome.tabs.insertCSS()
The second possibility would be to use a content script (content.js). But then you would have to use messaging to communicate between background.js and content.js.

How To Make Page To Interact With Background Page?

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();

Run a javascript function on click of popup icon of chrome extension

As chrome.browserAction.onClicked works only if there is no popup, is there any alternative method to fire a query when browser action icon is clicked?
Let me make myself clear..
I have more than one view i.e, html files in my extension. My default popup in index.html
Whenever I click on the icon I want to fetch some data from server. If I include this function in index.html or index.js, this function gets called every time I go to that page. Can anyone help me?
Thank you in advance.
What I would do is:
Have the behavior take place in the onload handler of the page. Since it sounds like the default popup page, index.html, can be loaded as time when the user is not creating the initial popup, I would create a page that is a dedicated initial popup load page that is not used anywhere else. This page could redirect to index.html or include it as an iframe.
Another option is to have index.html take a query string indicating how it is being used. Your initial popup could be index.html?init=1 and all other inclusions of the page simply use index.html. Then use window.location.search.substring(1) to test if a query string is present and take the appropriate action.
I'm also looking for an solution to this and I'm wondering if it is possible to start the browser action with no popup, detect the click, then set a popup with "setPopup()". If it works it doesn't seem like the nicest approach, I hope someone knows of a better solution.

Getting data from the options page to the injected code

My extension runs on an existing web page I do not control. I want to have an options page for it. What I haven’t figured out is how to get the option values from the injected code. localStorage isn’t shared, of course. I’ve tried using sendRequest / addListener in both directions, although it would be much preferable to push values from the options page to the injected code than they other way ‘round.
At the beginning, I simply put the option checkboxes on the manipulated page (the one the code is injected into), and those checkboxes set values in localStorage:
localStorage.showStuff = !!$(evt.target).attr(‘checked’);
Then I check those values in the code:
if (localStorage.showStuff == ‘true’) { … }
I moved the checkbox code to the options page and had it do a sendRequest when the options changed, and had my injected code have a listener for the message, but it doesn’t get the messages (my background page does, but that doesn’t help me). I also tried having the injected code hand a callback to the options page, but the sendResponse object only seems to work for the duration of the notify handler (not surprising, but I had to give it a try).
Right now my manifest’s permissions lists the foreign page ("http://example.com/*") and “tab”.
The one thing I know I can do is asynchronously query the options page via a callback, but the code doesn’t (and really can’t) work asynchronously without serious rewriting.
Any and all ideas welcome, thanks in advance.
i'm new to chrome extensions but when i tried to write/read localstorage from both, background script and option page it worked perfectly.
i haven't tried native localstorage but chrome's storage api.
take a look at this
code A: (set)
chrome.storage.sync.set({'key':'qwe'});
code B: (get)
chrome.storage.sync.get('key', function(response) {
console.log(response); // 'qwe'
});
u could put either code A in the background and code B in the option page or the other way around.
they are using the same storage.
this works for me. i hope u'll get there too.
The thing to remember is that only the background page is long-lived. The rest of the pieces of your chrome extension are transient (content scripts for the duration of the site navigation, options pages only while open, etc).
So you have to use messaging and save things using the background page. However, get ready for the storage API which should be landing soon. This will make things a lot easier for you!
Check it out here.

jQuery Mobile - Dialogs without changing hash

I have a search dialog that I am popping up and filling with jquery templates. After they make a selection I set a value on the current page. As such I don't need hashTags or anything like that, I just need a pop-up dialog that I can open and close programatically. I am currently opening the dialog with
$.mobile.changePage(dialog, { transition: "slide", changeHash: false });
and closing it with
dialog.dialog('close');
However, in certain cases (when the page is navigated to), closing the dialog refreshes the current page.
Is there a better way to interact with this?
Update:
I think I figured out what is going on. So for some reason, jquery mobile usually keeps 2 pages loaded on the DOM - one of which is invisible, you can verify this by running $('[data-role=page]') in the console. One page is the page you're on, the other is the page that you initially navigated to. Not quite sure why they choose to do that, but there you have it.
So they treat dialogs as a page navigation with a different transition even if the dialog is already in the DOM. Therefore, if you go directly to the page and then trigger a dialog, modifying the current page and closing it works fine - because the original page is always loaded in the DOM. However if you go to another page, than navigate to the page that triggers the dialog, and THEN trigger the dialog it destroys the current page so that the pages in the DOM are the initial one and the dialog. In that case it reloads that dialog-launching page entirely and you never get a chance to make any modifications.
Jeez. How do I interact with the jqm dialog widget directly?
You can try two other things. Both should work:
1 set DomChache
How about overriding JQM to keep the page your are firing the dialog from in the DOM? The docs say you can set data-dom-chache and override cleaning the page from the DOM.
If it only happens when you load this page in via AJAX (vs. loading it directly) you could make DOM-keeping dependend on your trigger page having data-page-external, assign DOM-chache="true" only when the dialog is openend and remove it again once the dialog is closed.
2 override JQM
I had the same problem you described and got it to work like this (requires hacking into JQM though...):
// inside transitionPages function
if ( !$(toPage).jqmData('internal-page')
{fromPage.data( "page" )._trigger( "hide", null, { nextPage: toPage } );}
}
My problem was that pagechanging to certain pages (same as dialog) caused the preceding page (where the dialog fired from) to be removed from the DOM, so I had a blank screen (when trying to go back). I added data-internal-page="true" to the pages, which should keep the preceding page intact and added the if-clause in JQM.
So now pageHide (and DOMcleanup) only fires, if I'm not going to a page labelled with data-internal-page="true"
Cheers!
I think I was having a similar problem. What I wanted to do was based on certain parameters, pop a dialog window on load (with that content on the same page), which they can close and view the page that loaded.
I could get it to pop on load using load, or the pageshow events, but when I clicked close that sent you back to the previous page in history, instead of just closing the dialog.
//target your 1st page content, here its id=success
//the modal content is in a page id=dialog and data-role="dialog"
$('#success').live('pageshow',function(){
window.setTimeout(function(){
$.mobile.changePage('#dialog','pop',false,false);
},1);
}
Its a hack, and just allows the page load to beat the dialog so it gets stuck in history. Then the default dialog close behavior for the dialog works as expected. Talk about a PITA, if they took a little more for the JQuery UI dialog it would have made things a ton easier.
And regarding your question: Have you looked at Jquery Mobile Actionsheet plugin
If you don't really require a page to be loaded, that should be ok.
Also helpful could be Cagintranet iPad popover, although you have to tweak the design to be fullscreen on mobile devices. If you require CSS/Jquery to do that let me know (I'm using this in a JQM plugin I'm writing)
Hope that helps.

Resources