I have a chrome extension and its popup.html has a link to a oauth/openid login page. To be exact to a page like this
I need this login page to be opened in a popup browser window with only an address bar. There should not be any other tool/menu bars. I tried window.open chrome.windows.create and window.showModalDialog methods.
All of them create a popup tab the way I wanted but none shows the address bar no matter what. When the popup.html is directly browsed via the browser, it shows the address bar, when the link is clicked. But not when the popup is loaded through the extension.
Since this page shows an oauth/openid login page, it is absolutely imperative that the user sees the address of the current page shown in the popup. No one would supply their facebook/google credentials to a page that does not have the address bar.
Any help is really appriciated.
I had a look around and it seems this is a known bug....
http://code.google.com/p/chromium/issues/detail?id=108875&q=popup%20bar&colspec=ID%20Pri%20Mstone%20ReleaseBlock%20OS%20Area%20Feature%20Status%20Owner%20Summary
You should star that for future updates and I think you should probably comment on your situation aswell.
The only way you could get the popup you want from your extensions code is to open a tab, get it to open the popup and then close the tab.....far from ideal.
But incase thats good enough for you here's some sample code....
manifest.json
{
"name": "Popup with adresse bar",
"version": "1.0",
"permissions": [
"tabs", "<all_urls>"
],
"browser_action": {
"default_title": "Popup with adresse bar.",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"manifest_version" : 2
}
popup.html
<!doctype html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
<a id='clicky' href='#'>clicky</a>
</body>
</html>
popup.js
clicky = function() {
chrome.tabs.create({
url: 'open.html#' + 'http://www.google.com',
active: false
});
}
onload = function() {
document.querySelector('#clicky').onclick = clicky;
}
window.onload = onload;
open.html
<script src='open.js'></script>
open.js
window.close();
window.open(window.location.hash.substr(1), '…', '…');
Ok I am going to give this question a try. I understand what you are talking about with the address bar being hidden. For instance, my rem-i-con extension. If the user hasn't registered it will open a new tab, that will then ask them to create a account or login. But the address bar is blank.
However, in my popup.html file, I have a few links that do open a new tab with the address shown in the window. I understand you want a model type window but I am not sure that can be done. Here is something you can try.
Have a regular link asdd
When clicked you can have listener that watches the tab that has just been opened. This you could do easily by scanning the active tabs.
Then once the tab is closed, you could then have your popup.html file reload. You will need to use a background.html file for this.
If this works, then you could just automate the tag click.
Related
I know it's possible to show a popup when clicking on the extension icon (top right of the browser, to the right of the address bar): chrome.browserAction
Also here is how to create an Options page, that will often have an URL like:
chrome-extension://ofodsfyizzsaaahskdhfsdffffdsf/options.html
Question: how is it possible to make that a single click on the extension icon opens the options.html page in a new tab?
You can use something like this in your background script:
background.js
chrome.browserAction.setPopup({popup:''}); //disable browserAction's popup
chrome.browserAction.onClicked.addListener(()=>{
chrome.tabs.create({url:'options.html'});
});
manifest.json
...
"browser_action": {
"default_title": "Options"
},
"background": {
"scripts": ["background.js"],
"persistent": true
}
...
I'm trying to build a somehow dummy Chrome extension. I want it to run only in specific pages, so I'm using a Page Action.
Let's say I want the page action to run on the Instagram website, then (accordingly the docs), I would need something like this on my manifest.json right?
{
"manifest_version": 2,
"name": "Some name",
"version": "0.0.3",
"description": "Some description",
"content_scripts": [
{
"matches": [
"https://www.instagram.com/*"
],
"js": ["content.js"]
}
],
"page_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["background.js"]
}
}
while the content script runs only on instagram pages as one would expect, the browser extension is not clickable (gray look, and when I click most options are not clickable).
this makes impossible to act upon extension button click. In my background.js I have:
function click(tab) {
console.log('click from ' + tab);
}
chrome.pageAction.onClicked.addListener(click);
that never gets called.
So, what's wrong that makes impossible to act upon extension click on some pages?
Note: I saw this question/answer, but couldn't find the problem/solution How can I add a click for pageAction?
You have to call pageAction.show in order for your pageAction button to be enabled (clickable).
The pageAction documentation says (emphasis mine):
You make a page action appear and be grayed out using the pageAction.show and pageAction.hide methods, respectively. By default, a page action appears grayed out. When you show it, you specify the tab in which the icon should appear. The icon remains visible until the tab is closed or starts displaying a different URL (because the user clicks a link, for example).
With a manifest.json content_scripts entry
Because you already have a content script that runs on the page you desire to have this function on, probably the easiest way to do this is to have your content script send a message to your background script telling it to show the page-action button for that tab.
Your content script could look something like:
chrome.runtime.sendMessage({type: showPageAction});
Your background script could look something like:
chrome.runtime.onMessage(function(message, sender, sendResponse) {
if(typeof message === 'object' && message.type === 'showPageAction') {
chrome.pageAction.show(sender.tab.id);
}
});
Without a manifest.json content_scripts entry
If you did not have a content script, you would probably want to use a webNavigation.onCompleted listener, or tabs.onUpdated listener, to listen for a change in the tab's URL in order to determine that the page-action button should be shown. Obviously, the trigger for calling pageAction.show() does not have to be the URL which is currently displayed in the tab, but that is the most common.
I'm trying to build a basic Chrome extension that, from a browser action popup, opens a website in a new tab, and fills in the login credentials. I can get the Chrome extension to open the new page but can't seem to get it to input text into the input fields.
Manifest.json
{
"manifest_version": 2,
"name": "Vena",
"description": "This extension will allow users to login to vena accounts",
"version": "1.0",
"browser_action": {
"default_icon": "images/icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
popup.html
<!doctype html>
<html>
<head>
<title>Auto-Login</title>
<script src="popup.js"></script>
</head>
<body>
<h1>Login</h1>
<button id="checkPage">Login!</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function() {
var newURL = "https://vena.io/";
chrome.tabs.create({ url: newURL });
var loginField = document.getElementsByClassName('js-email form-control input-lg');
var passwordField = document.getElementsByClassName('js-password form-control input-lg');
loginField.value = 'gsand';
passwordField.value = '123';
}, false);
}, false);
How do I fill in the information in the input areas of the new tab?
Another time, you may want to use something other than a popup (e.g. just a plain browser action button, or a panel) to test out your functionality. It is easier to debug things other than a popup due to the fact that the popup will disappear under so many conditions. Once you have the basic functionality debugged, you can move it into a popup and deal with the issues specific to using a popup.
Issues
You need to use a content script to interact with web pages:
The primary issue is that you have to use a content script to interact with a web page, such as manipulating the DOM, as you desire to do. Content scripts have to be injected into the web page. This can be done with a content_scripts entry in your manifest.json, or with chrome.tabs.executeScript() from JavaScript that is in the background context (background scripts, event scripts, popups, panels, tabs containing pages from your add-on, etc.). For what you are doing, chrome.tabs.executeScript() is the way to go.
Additional issues:
chrome.tabs.create() is asynchronous. You need to wait for the callback to execute so the tab exists in order to inject a content script. You can not inject scripts into a tab that does not yet exist. Note: You could use other, more complex, methods of determining when to inject the content script, but the callback for chrome.tabs.create() is a good way to do it in this case.
Once you create the new tab, you want to inject a script. This is not the "active tab", so you need to add "https://vena.io/*" to your permissions in your manifest.json.
The elements you desire to interact with are not immediately available on the page when the content script is run. You need to wait until they are available. I just used a setTimeout loop to poll until the elements are available. I chose to poll on 250ms intervals a maximum of 100 times (25 seconds). The elements were there each time after the first delay.
document.getElementsByClassName() returns an HTMLCollection, not a single element.
Popups close when you activate a different tab. Once the popup is closed/destroyed, you can not do any more processing within the code for the popup. In order to get around that:
In your chrome.tabs.create(), include active:false to prevent the new tab from becoming active immediately.
Call chrome.tabs.update() in the callback for chrome.tabs.executeScript() to active the tab once the content script has been injected (i.e. when you are done with all the processing you are going to do in the popup).
Code
Changes were only needed in your manifest.json and popup.js.
manifest.json
{
"manifest_version": 2,
"name": "Vena",
"description": "This extension will allow users to login to vena accounts",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab", //This is not needed as you never interact with the active tab
"https://vena.io/*"
]
}
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('checkPage');
checkPageButton.addEventListener('click', function() {
var newURL = "https://vena.io/";
//Must not make the tab active, or the popup will be destroyed preventing any
// further processing.
chrome.tabs.create({ url: newURL,active:false }, function(tab){
console.log('Attempting to inject script into tab:',tab);
chrome.tabs.executeScript(tab.id,{code:`
(function(){
var count = 100; //Only try 100 times
function changeLoginWhenExists(){
var loginField = document.getElementsByClassName('js-email form-control input-lg')[0];
var passwordField = document.getElementsByClassName('js-password form-control input-lg')[0];
//loginField and passwordField are each an HTMLCollection
if( loginField && passwordField ){
loginField.value = 'gsand';
passwordField.value = '123';
} else {
if(count-- > 0 ){
//The elements we need don't exist yet, wait a bit to try again.
//This could more appropriately be a MutationObserver
setTimeout(changeLoginWhenExists,250);
}
}
}
changeLoginWhenExists();
})();
`},function(results){
//Now that we are done with processing, make the tab active. This will
// close/destroy the popup.
chrome.tabs.update(tab.id,{active:true});
});
});
}, false);
}, false);
May need use document.execCommand('insertText', false, text);
Depending on the page, you may need/want to use:
document.execCommand('insertText', false, textValue);
If you do so, you will need to first select/focus the desired element. This would be instead of setting the .value property. Which you use will depend on what you are actually doing and the composition of the page you are altering. For the specific example in the question, setting the element's .value property works. For inserting text, using `document.execCommand('insertText') is more generally applicable.
May need a MutationObserver
In the above code I use a setTimeout() loop to delay until the desired elements exist. While that works in the above case, depending on your use case, it may be more appropriate for you to use a MutationObserver. Largely, which to use will depend on how immediately you need to respond to the desired elements being added and what type of load you are putting on the page by looking for the elements. For more information about watching for DOM changes see: Is there a JavaScript/jQuery DOM change listener?
UI comment
Currently you have a popup that has a single button: "Login". From a user interaction point of view, it would probably be better to just use a plain browser action button. If you are intending to add functionality to your popup, then go ahead and keep the popup. If you are not going to add functionality, it does not make a lot of sense to force your user to click twice (click: open popup, then click: login) when they could have just clicked once.
Use an actual Password Manager
If this is functionality that you desire, rather than just something you are putting together just to learn, you should use an actual Password Manager. The functionality of securely storing passwords and inserting them appropriately in websites is non-trivial. You can easily make mistakes that result in compromising your security. I strongly recommend that you investigate the various ones available and choose one which fits your needs. Basically, all the ones that I have seen would easily provide you with the functionality you have at this time: open a popup; select the site; go to the site and fill in the user name and password. A password manager is a very significant project. It is not a project to be taken on lightly, or for someone who is not experienced in security issues.
I am trying to make a simple chrome extension.
It is supposed to add an item "Open new tab" in the 'windows system tray chrome icon context menu' (similar to how the checker plus for gmail extension has done; see the second image given below).
when I click the option, chrome is supposed to (check if any window is open. If yes, then it is supposed to) open a new tab page. If no windows are open, then it is supposed to open a new chrome window with the new tab page showing.
What I have done till now:
manifest.json
{
"manifest_version": 2,
"name": "Open New Tab",
"description": "This extension open a new tab page",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"background":{
"scripts":["background.js"],
"persistent": false
},
"permissions": [
"background",
"activeTab"
]
}
background.js
chrome.browserAction.onClicked.addListener(function(tab)
{
chrome.tabs.create({ url: "chrome://newtab" });
}
);
background.html
<html>
<head>
<script>
chrome.browserAction.onClicked.addListener(function(window)
{
chrome.windows.create({url: "chrome://newtab", type: "normal"});
}
);
</script>
</head>
</html>
I have already loaded this extension.
The effects of my extension on chrome so far:
1) Chrome window is already open.
My icon shows up in the list of extensions and is clickable.
On clicking, a 'new tab' page is opened in the same window. This is correct. (Though I don't need this. For now, let it be.)
2) Chrome window is closed, and chrome is allowed to run in the background. Rightclick the chrome tray icon. My extension menu 'Open a new tab' shows up in the menu.
This is also correct. On clicking it, a new chrome window is created. (Currently, I have not yet checked if a window already exists. That is to come later.).
The problem is that, in the new window that opens, instead of the 'new tab' page, chrome automatically opens the 'chrome://extensions' URL. This is wrong, and I cannot understand why the extensions page is opening. I want to open the new tab page, and i am passing the 'chrome://newtab' URL. How do I make chrome open the new tab page from here? Chrome works correctly when I start it from my desktop icon or windows start menu. So, the problem seems to be something with my code.
Any help is appreciated.
Listen to chrome.windows.onCreated event, when right clicking chrome tray icon, a new window would be launched, then you could create a new tab in the event handler.
chrome.windows.onCreated.addListener(function(window) {
chrome.windows.getAll(function(windows) {
if (windows.length === 1) {
chrome.tabs.create({windowId: window.id, url: "chrome://newtab"});
}
});
});
I am building a Chrome Extension and I want to inject and run Javascript code into a tab.
For example :
chrome.tabs.query({active: true, lastFocusedWindow: true}, function(selectedTab) {
chrome.tabs.executeScript(selectedTab[0].id, {code: code_});
});
With the code_ variable being :
$('#gbqfq').val('test');
$("#gbqf").submit();
$('#rso > div.srg > li:nth-child(1) > div > h3 > a').click();
This simple script is meant to be executed on google.com and should type and search "test" and click on the first result.
The problem is that after submitting the request, the tab changes its URL and thus loads another page. And it seems that when the page loads, all the scripts injected by chrome.tabs.executeScript disapears.
Is there a way to run a single script through different pages in the same tab ?
My extension should allow the user to run his own script, so it is complicated (maybe impossible?) to know in advance at which point of the script the tab is expected to reload (in order to use several chrome.tabs.executeScript calls).
Here is the manifest.json of my Extension, I am only using a popup (no background, no content_scripts) :
{
"manifest_version": 2,
...
"options_page": "options.html",
"permissions": [
"storage",
"unlimitedStorage",
"tabs",
"windows",
"http://*/*",
"https://*/*"
],
"browser_action":
{
"default_popup": "popup.html"
}
}
No, you cannot run the same script after a tab navigates away, since the JavaScript context in which the script lives is torn down.
So you will need to inject a script again after the page loads.
You probably want to do something along these lines:
Inject your submitting script and save the tab ID.
Initiate a submit.
Listen to chrome.tabs.onUpdated filtered by tab ID above and status "complete".
Check that the URL is the one you expected, then inject your data-gathering script.