Open extension popup when click on context menu - google-chrome

I have to make an extension that when clicked on text in the context menu, in callback opens the extension menu popup.
chrome.runtime.onInstalled.addListener(function() {
var context = "selection";
var title = "Google for Selected Text";
var id = chrome.contextMenus.create({"title": title, "contexts":["selection"],
"id": "context" + context});
});
// add click event
chrome.contextMenus.onClicked.addListener(onClickHandler);
// The onClicked callback function.
function onClickHandler(info, tab) {
var sText = info.selectionText;
var url = "https://www.google.com/search?q=" + encodeURIComponent(sText);
//what i have put here to open extension popup
};
In this case, when I click on the menu I open a new tab with this search.

There is no way of opening the default browser action popup programmatically. A work around is use content scripts to open a modal or a lightbox and show the contents of your popup.
Another way would be - within the clickhandler of your context menu item, create a new tab and make it inactive and then pass that tab to chrome.windows.create api to create a new popup window.
chrome.tabs.create({
url: chrome.extension.getURL('popup.html'),
active: false
}, function(tab) {
// After the tab has been created, open a window to inject the tab
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true
});
});
It is just a work around. Hope it helps.

It is now possible to open a browser action popup programmatically from inside the handler for a user action.
browser.menus.create({
id: "open-popup",
title: "open popup",
contexts: ["all"]
});
browser.menus.onClicked.addListener(() => {
browser.browserAction.openPopup();
});
You can read more about it here.
Edit:
This feature is only available as of Firefox 57. In Chrome, it is only available in the dev channel.
Sources: chrome/common/extensions/api/_api_features.json - chromium/src - Git at Google

Unfortunately, it cannot be done.
Chrome API doesn't provide a method to open extension popup programmatically. The Chromium team rejected the feature request for such an option with an explanation that:
The philosophy for browser and page action popups is that they must be
triggered by user action.
Here's the source.

You can use the chrome.window API (documentation here).
What you want is something like this :
chrome.windows.create({
url : "http://yourPopupUrl.com"
focused : true
type : "popup"});
This will open a new windows in popup mode (without the top menu bar) and load the "http://yourPopupUrl.com".

Related

Making Chrome extension make an existing tab active and canceling the incoming request with chrome.webRequest.onBeforeRequest listener

I'm building a search app and when a user tries to navigate to the URL of a search result, I want to:
A) open a new tab with that URL if they don't already have that URL open in an existing tab, or
B) if they already have a tab with that URL open, make that existing tab active and refrain from opening another new tab with that same URL.
Separately from the code below, I have a currentTabs dict that's keeping track of the tabId and URL of each open tab so that I can compare the incoming URL to the already open URLs.
I'm trying to add a listener on
chrome.webRequest.onBeforeRequest
to accomplish this. I'm using a query string like ?from_my_app=true so that I only implement this behavior on links from my app rather than any time someone tries to navigate to a URL they already have open. My code looks like this:
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if (details.url.match(/?from_my_app=true/)) {
var strippedUrl = (details.url.split('?from_my_app=true')[0];
var matchedUrl;
if (currentTabs.tabs) {
// get the first pre-existing tab that has this url
matchedUrl = currentTabs.tabs.filter(x => x[1] == strippedUrl)[0];
}
if (matchedUrl) {
// make the pre-existing tab with this url active
// and cancel the opening of a new tab opening this url
chrome.tabs.update(matchedUrl[0], { active: true });
return { cancel: true }
} else {
// if this URL isn't already open in a tab, remove the
// ?from_my_app=true query string and open it in a new
// tab
return { redirectUrl: strippedUrl };
}
}
},
{ urls: ["<all_urls>"] },
["blocking"]
);
The issue I'm running into is that the
return { cancel: true }
executed when a URL is already open in another tab is causing the tab to not load at all and say " is blocked.
Requests to the server have been blocked by an extension." Clearly I'm using the API wrong - the behavior I'm looking for is for it to basically make the incoming request "fail silently" and just do the navigating to the existing tab while not opening a new tab at all. Is there a clean way to do this?

Opening a PDF Blob in a new Chrome tab (Angular 2)

I am loading a PDF as follows (I am using Angular 2, but I am not sure that this matters..):
//Inside a service class
downloadPdf = (id): Observable<Blob> => {
let headers = new Headers();
headers.append("Accept", "application/pdf");
return this.AuthHttp.get(this.pdfURL + id, {
headers: headers,
responseType: ResponseContentType.Blob
}).map(res => new Blob([res.blob()], {type: "application/pdf"}));
}
//Inside a click handler
this.pdfService.downloadPdf(this.id).subscribe((data: Blob) => {
let fileURL = window.URL.createObjectURL(data);
window.open(fileURL);
});
This code runs nicely in Firefox. In Chrome, a new tab briefly flashes open and closes. When I debug and I manually put surf to the object URL, Chrome can open it just fine.
What am I doing wrong here?
The opening of a new tab got blocked by an adblocker.
It can not work, new popup will be blocked by browser, because of it was created from callback which is not a trusted event, to make it work it must be called directly from click handler, or you have to disable bloking popups in your browser.
Chrome will only allow this to work as wanted if the ajax call returns in less than a second. More there

URL bar not updated in Chrome after Backbone routing

I have a Backbone application which, at one point, opens a new tab in the browser. After the execution in the new tab is complete a javascript will be triggered (in that new tab) to trigger routing in the opener window. Javascript code looks like this:
window.onunload = window.onbeforeunload = function(e){
opener.router.navigate("start",{trigger: true});
};
window.close();
This works great, the 'start' route is executed and the correct result is shown in all browsers (including Chrome). But in Chrome, the url bar is not updated with the new url (eg. ../something#start), instead the original url for the opening window remains in the address bar.
In IE and Firefox the url bar shows the correct url. Is there some way to achieve this behaviour in Chrome also?
Any input appreciated!
Instead of trying to make a call to the router directly from the tab that's about to be closed, have you tried triggering a Backbone event (which the "opener window" would be listening to) instead?
So change:
window.onunload = window.onbeforeunload = function(e){
opener.router.navigate("start",{trigger: true});
};
window.close();
to:
window.onunload = window.onbeforeunload = function(e){
Backbone.trigger('routeChange');
};
window.close();
And include a listener to the routeChange event in the "opener window's" view with a callback function which executes router.navigate():
opener.listenTo(Backbone, 'routeChange', function(e) {
opener.router.navigate('start',{trigger: true});
});
Let me know if that helps.

chrome extension API for refreshing the page

Is there an API to programmatically refresh the current tab from inside a browser action button? I have background page configured, which attaches a listener via:
chrome.browserAction.onClicked.addListener(function(tab) { ... });
So the callback function retrieves a reference to the tab that it was clicked from, but I don't see an API anywhere to refresh/reload that tab.
I think what you're looking for is:
chrome.tabs.reload(integer tabId, object reloadProperties, function callback)
Check out tabs API() documentation for more information.
The API for chrome.tabs.getSelected(), which the accepted answer uses, has been deprecated. You should instead get the current tab and reload it using something like the following:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(arrayOfTabs[0].id, {code: code});
});
Or perhaps:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
chrome.tabs.reload(arrayOfTabs[0].id);
});
I had no real luck with the second version, though other answers seem to suggest it should work. The API seems to suggest that, too.
I recommend using chrome.tabs.executeScript to inject javascript that calls window.location.reload() into the current tab. Something like:
chrome.tabs.getSelected(null, function(tab) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(tab.id, {code: code});
});
Reference here
More specifically:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.reload(tab.id);
});
You can also use this:
chrome.tabs.reload(function(){});
reload function params: integer tabId, object reloadProperties,
function callback
Reference: http://developer.chrome.com/extensions/tabs.html#method-reload
if you want to reload all the tabs which have loaded completely and are active in their window
chrome.tabs.query({status:'complete'}, (tabs)=>{
tabs.forEach((tab)=>{
if(tab.url){
chrome.tabs.update(tab.id,{url: tab.url});
}
});
});
you can change the parameter object to fetch only active tabs as {status:'complete', active: true} refer to query api of chrome extensions
Reason for not using chrome.tabs.reload :
If the tab properties especially the tab.url have not changed, tab does not reload. If you want to force reload every time, it is better to update the tab URL with its own tab.url which sends the event of the change in property and tab automatically reloads.

Open a "Help" page after Chrome extension is installed first time

I am new to Chrome extension. I have a question about how to make the extension to open a "Help" page automatically after installation. Currently, I am able to check whether the extension is running the first time or not by saving a value into localStorage. But this checking is only carried out when using click the icon on the tool bar. Just wondering if there is a way that likes FF extension which uses the javascript in to open a help page after the installation. Thanks.
Edit:
Thanks for the answer from davgothic. I have solved this problem.
I have another question about the popup. My extension checks the url of current tab,
if OK(url){
//open a tab and do something
}
else{
//display popup
}
Is it possible to show the popup in this way?
Check this updated and most reliable solution provided by Chrome: chrome.runtime Event
chrome.runtime.onInstalled.addListener(function (object) {
let externalUrl = "http://yoursite.com/";
let internalUrl = chrome.runtime.getURL("views/onboarding.html");
if (object.reason === chrome.runtime.OnInstalledReason.INSTALL) {
chrome.tabs.create({ url: externalUrl }, function (tab) {
console.log("New tab launched with http://yoursite.com/");
});
}
});
Add this to your background.js I mean the the page you defined on manifest like following,
....
"background": {
"scripts": ["background.js"],
"persistent": false
}
...
UPDATE: This method is no longer recommended. Please see Nuhil's more recent answer below.
I believe what you need to do is put something like this into a script in the <head> section of your extension's background page, e.g. background.html
function install_notice() {
if (localStorage.getItem('install_time'))
return;
var now = new Date().getTime();
localStorage.setItem('install_time', now);
chrome.tabs.create({url: "installed.html"});
}
install_notice();
As of now (Aug 2022) the right way to execute code on first install or update of an extension using Manifest V3 is by using the runtime.onInstalled event.
This event is documented here: https://developer.chrome.com/extensions/runtime#event-onInstalled
There is one example for this exact case in the docs now:
https://developer.chrome.com/docs/extensions/reference/tabs/#opening-an-extension-page-in-a-new-tab
Note: This example above is wrong as the callback function parameter is Object with the key reason and not reason directly.
And another example here (this one is correct but does not open a tab):
https://developer.chrome.com/docs/extensions/reference/runtime/#example-uninstall-url
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === chrome.runtime.OnInstalledReason.INSTALL) {
// Code to be executed on first install
// eg. open a tab with a url
chrome.tabs.create({
url: "https://google.com"
});
} else if (details.reason === chrome.runtime.OnInstalledReason.UPDATE) {
// When extension is updated
} else if (details.reason === chrome.runtime.OnInstalledReason.CHROME_UPDATE) {
// When browser is updated
} else if (details.reason === chrome.runtime.OnInstalledReason.SHARED_MODULE_UPDATE) {
// When a shared module is updated
}
});
This code can be added to a background service worker: https://developer.chrome.com/docs/extensions/mv3/migrating_to_service_workers/
It would be better to place a "version" number so you can know when an extension is updated or installed.
It has been answered here:
Detect Chrome extension first run / update
All you need to do is adding the snippet below to your background.js file
chrome.runtime.onInstalled.addListener(function (object) {
chrome.tabs.create({url: `chrome-extension://${chrome.runtime.id}/options.html`}, function (tab) {
console.log("options page opened");
});
});