How can I know if my Chrome Extension is called from a New Tab page? - google-chrome

My Chrome Extension has a popup with a few links, which I would like to be opened in the current tab if it's a New Tab page, or open in a new tab otherwise. So I believe I need to know the active tab's URL. Or is there another way to identify a New Tab?
I'd like to use the "activeTab" permission rather than "tabs" - I want the user to see as few permissions listed as possible.
The only way I've found to identify the tab's URL is by using a background page and
chrome.browserAction.onClicked.addListener(function(tab))
But this is not compatible with having a popup defined in the manifest. I can set the popup page programatically, but I can't see a way to make the popup appear. Is there a way to do that?
When I have default_popup defined in the manifest I use
document.addEventListener('DOMContentLoaded', function ())
to launch the related code, so no reference to the active tab is available. Is there another way to run the code, or to get the active tab?
Thanks.

The activeTab permission allows you to "Get the URL, title, and favicon for that tab via an API that returns a tabs.Tab object". So, to get the current tab URL from the popup you can do:
chrome.tabs.query( {active:true, currentWindow: true}, function(tabs) {
currentUrl = tabs[0].url;
});

Related

Changing chrome extension html using chrome storage event listener

With this code I want to create an event listener for whenever chrome storage updates.
I want 2 things to happen when the event listener is triggered:
The code will console log the updated values. This part works.
I want the HTML for the extension (the document that opens in the corner when you click the icon) to update and render the data value that is in chrome storage. This is that part I need help with.
chrome.storage.onChanged.addListener(function(changes, namespace) {
//part 1
console.log('New data type is %s. New value is %s',
changes['type'].newValue, changes['data'].newValue)
//part 2
document.getElementById('output').innerHTML =
changes['data'].newValue
});
I realize that calling "document" inside the function doesn't make sense, but I'm unsure how to move forward to get it to render in the extension's HTML.
I tried creating an event listener for when the context menu is accessed (users can update the chrome storage but clicking a button in the context menu) but I couldn't get it to work. Also the event should trigger when chrome storage is updated, not when the context menu is simply accessed.
Right now I get this error:
Error in event handler: TypeError: Cannot set property 'innerHTML' of null
(There is an element with id 'output', so that isn't the problem)
Thanks for your help!
The background script runs in a separate hidden background page. It's not related to the browserAction or pageAction popup page, it doesn't have any of the popup page elements, its DOM is empty except for the auto-generated script tags of the background scripts.
The popup is also a separate page and just like any normal page its environment/DOM exists only when the page is shown. You can't modify it when it's not shown. You can't show it from your code in general case either.
Solution 1
Put that onChanged listener in popup.js script that's loaded in your popup.html (declared as "browser_action": {"default_popup":"popup.html"} in your manifest.json) using the standard <script src="popup.js"></script> tag. It will update the popup page if it's shown, and to display the current values when the popup opens read them with chrome.storage.local.get or chrome.storage.sync.get depending on which storage you're using in your extension.
Solution 2
Use chrome.notifications API to show a small notification at the bottom of the screen, see also the official demo extensions.
Solution 3
Use chrome.browserAction.setBadgeText to display short text like a temperature right under the extension icon. Don't forget to declare at least "browser_action": {} in your manifest.json.

Google Chrome - add to homescreen - force refresh

I have a website with "add to homescreen" enabled - i.e. I have got a manifest.json file with "display": "standalone".
The problem I'm having is when I open the website via the homescreen shortcut, it will resume from when I last accessed it. I have to pull to refresh to make it fetch the latest content.
My question is, is it possible to make it do a refresh every time it is accessed?
If you'd like to take specific action inside of your web app whenever it moves from the "background" to the "foreground" again, you could listen for the appropriate events using the Page Lifecycle API.
The most straightforward way of doing this would probably be to listen for visibilitychange events, and programmatically refresh your data source when you detect that the current visibilityState has transitioned to 'visible'.
This could look like:
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
// Your refresh logic goes here.
}
});

How can I open my extension's pop-up with JavaScript?

I am trying to write a JavaScript function that will open my extension like when the extension icon is clicked. I know how to open my extension in a new tab:
var url = "chrome-extension://kelodmiboakdjlbcdfoceeiafckgojel/login.html";
window.open(url);
But I want to open a pop-up in the upper right corner of the browser, like when the extension icon is clicked.
The Chromium dev team has explicitly said they will not enable this functionality. See Feature request: open extension popup bubble programmatically :
The philosophy for browser and page action popups is that they must be triggered by user action. Our suggestion is to use the new html notifications feature...
Desktop notifications can be used progammatically to present the user with a small HTML page much like your popup. It's not a perfect substitution, but it might provide the type of functionality you need.
Chrome team did create a method to open the popup programmatically, but it's only enabled as a private API, and plans to make it generally available have stalled due to security concerns.
So, as of March 2018 as of now, you still can't do it.
Short answer is that you cannot open browserAction programmatically. But you can create a dialog with your content script which emulates your browserAction and display that isntead (programmatically). However you won't be able to access your extension's background page from this popup directly as you can from your popup.html. You will have to pass message instead to your extension.
As mentioned there is no public API for this.
One workaround I have come up with is launching the extension as an iframe inside a content script with a button click. Whereby the background script emits the extension URL to the content script to be set as the iframe's src, something like below.
background.js
browser.runtime.onMessage.addListener((request) => {
if (request.open) {
return new Promise(resolve => {
chrome.browserAction.getPopup({}, (popup) => {
return resolve(popup)
})
})
}
})
content-scipt.js
const i = document.createElement('iframe')
const b = document.createElement('button')
const p = document.getElementById('some-id')
b.innerHTML = 'Open'
b.addEventListener('click', (evt) => {
evt.preventDefault()
chrome.runtime.sendMessage({ open: true }, (response) => {
i.src = response
p.appendChild(i)
})
})
p.appendChild(b)
This opens the extension in the DOM of the page the script is running on. You will also need to add the below to the manifest.
manifest.json
....
"web_accessible_resources": [
"popup.html"
]
....
You could emulate the popup by displaying a fixed html element on the page in the same location the popup would be and style it to look like the popup.
I had the same requirement: When the user clicks on the extension icon a small popup should open. In my case, I was writing an extension which will give updates on selective stocks whenever the icon is clicked. This is how my popup looked.
If you were having the same requirement then please read the answer below.
This is how my manifest.json file looked.
All the heavy lifting was handled by manifest.json file only. There is a section browser_action inside which there is a key called default_popup, just put the name of the HTML file that you want the popup to display.
I wanted my extension to work on all the pages that's why I added the attribute matches under content_scripts. I really didn't need to put the jquery file jquery-3.2.1.js inside the js array but the extension manager was not allowing me to keep that array empty.
Hope this helps, do comment if you have any doubt regarding the answer.

Open chrome extension in a new tab

I have implemented a chrome extension. Was wondering if the popup.html can be opened in a new tab? Every single click on the page, and the popup disappears :( .. Was wondering if I can stick it to the page or is there a way to open the extension in a new page?
Yes, a popup page is just a normal extension page, you can do the following to open a new popup tab from the background page. I use that every time when the user first installs the extension, I open the about page, you can do the same for the popup page.
chrome.tabs.create({url: 'popup.html'})
For one of my extensions, My Hangouts, I have a small "open as tab" button within the popup, I bind the click event for that link to execute this:
chrome.tabs.create({url: chrome.extension.getURL('popup.html#window')});
The reason why I passed the hash is because I wanted to add more content when the user opens it in a popup because there is more real estate to play with.
Within the popup, I use normal JavaScript to differentiate whether I opened the tab in the new tab page or in a normal page like the following:
if (window.location.hash == '#window') {
this.displayAsTab = true;
}
You can do tricks like this to make your extensions user experience better.
here is the same issue: Chrome Extension: onclick extension icon, open popup.html in new tab
use:
chrome.tabs.create({'url': chrome.extension.getURL('popup.html')}, function(tab) {
// Tab opened.
});
property "pinned" to stick the tab.

Is it possible to determine a tab's opener within a Google Chrome extension?

I am looking for a way to determine a given tab's opener (parent tab) within a Google Chrome extension.
I've looked at the documention for Tab but there doesn't really seem to be anything that would yield this information. http://code.google.com/chrome/extensions/tabs.html
I've tried injecting this content script into pages (thinking I could pass the value to my background page):
alert(window.opener);
.. but it just yields null.
The best thing I've come up with so far is to keep track of the currently focused tab, and whenever a new tab is created, just assume that the focused tab is the opener/parent of the new tab. I believe this would de facto identify the parent tab correctly most of the time since background tabs rarely (are allowed to) open new pages. However, it seems kludgey and potentially inaccurate at times -- for example, if another extension opened a new tab, this method may misidentify the new tab's opener.
Update: it is now possible to reliably determine a tab's opener tab within a Chrome extension natively using the newly added webNavigation API, and specifically by hooking the onCreatedNavigationTarget event.
https://code.google.com/chrome/extensions/trunk/webNavigation.html
Chrome has added an experimental extension API which can accomplish this -- specifically webNavigation.onBeforeRetarget. http://code.google.com/chrome/extensions/experimental.webNavigation.html
However since this is still experimental (not usable in Chrome stable versions or releasable on the Chrome Web Store) I have ended up using another approach.
Basically:
In content_script.js:
chrome.extension.sendRequest({
request: {
op: "pageLoadStarted",
url: document.location.href,
referrer: document.referrer
}
});
In background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
console.log('onRequest: ' + JSON.stringify(request));
console.log(JSON.stringify(sender));
});
This approach allows me to obtain the referrer of a tab, which I can then correlate with an existing tab's url. This isn't always a one-to-one mapping, so I do some additional magic such as preferring the currently selected tab as the opener if its url matches the new tab's referrer.
This really is just a hack to approximate the functionality that would be provided more simply and accurately by webNavigation.onBeforeRetarget or window.opener.
Further investigation has revealed that onCreatedNavigationTarget() does not always fire when you think it would to indicate an opener-opened relationship.
An additional hint can sometimes be found in the Tab object returned by chrome.tabs.onCreated/onUpdated in the .openerTabId parameter.
A comprehensive solution will probably have to rely on multiple of the methods described in these answers.
port.onMessage.addListener(
function(msg) {
var tabid = port.sender.tab.openerTabId;
console.log("Received message from tab that was opened by tab id : " + tabid);
// reliably shows the tab id of the tab that opened
// the tab sending the message
});