First of all, I am a newbie in chrome extension development. I am developing a chrome extension to collect user inputs from a form on a specific webpage.
In my manifest.json, I have added javascripts to be used for this purpose inside "content_scripts" and they are invoked when the matched URL loads. In my javsacript, I have added eventlisteners for triggering functions when a button is clicked.
The problem I am facing is that, evenlisteners work fine and the required functions get executed when the button is clicked for first time.
But when the button is clicked for second time, it does not trigger the listener.
Can anyone please recommend me a way to overcome this issue?
Content script part of my manifest.json:
"content_scripts": [
{
"matches": ["*://domain/pathtofile*"],
"all_frames": true,
"js": ["myscript.js"],
"run_at": "document_end"
}
]
And in "myscript.js", I use this:
document.getElementById("elementid").addEventListener("click", functiontocall);
Thank you
Sujith
------ Edit ------
Extension I am developing is for a specific client and this is an unlisted extension in chrome store. So I am not able to provide the URL due to NDA with client.
The URL (example: "http://www.domain.com/urlpath/form.php") has a DIV inside it, which contains an HTML form. So when this URL is loaded, it matches with the manifest and loads a javascript "myscript.js". In "myscript.js", I have written a code:
document.getElementById("formbuttonelement").addEventListener("click", getFormData);
The function "getFormData()" just contains basic javascripts to take values from each form element and prepare a query string and send to another PHP script ("collectForm.php") using AJAX.
After the form button is clicked, the DIV element will close. In the web page, there is a button to open this DIV (HTML form) again, and user can input data in form and click "formbuttonelement" again to submit form.
So, my problem is that, when I open the URL "http://www.domain.com/urlpath/form.php" for the first time, everything works as expected, including the addEventListener part and I can get the form data in "collectForm.php". And, as mentioned earlier, the DIV element will close.
But when the DIV is opened again (which does not load the URL again), addEventListener is not working. I presume that it is because the URL is not reloading, thereby not invoking "myscript.js" again.
I am looking for an option to restart event listener even if the web page is not reloaded.
I hope I have explained the situation.
Thanks & Regards
Sujith
Related
To simplify the scenario, lets say I'm working on an extension that just contains: alert("Hello") whenever you load a page in example.com. Relevant manifest.json part:
"content_scripts":
[
{
"matches": ["*://*.example.com/*"],
"js": ["script.js"]
}
]
When I first visit the website, it works fine. But the problem is some of the links in the website don't reload the page, they just manipulate the DOM. So a link for example will take you to example.com/foo, the script doesn't run. Even when I return to the home page, it doesn't run again, and all the edits that were made the first time are removed.
How do I make the add-on recognize that the page has changed, and rerun the script?
After spending hours on this, I was finally able to achieve what I want, though not in the way I expected it would be. This is my solution:
document.addEventListener("click", function(){
editStuff();
});
This works just fine for the website I'm making the add-on for. There is some wasted computational power, as some clicks don't really require the function to work again, but its minimal in my use case.
I have a chrome extension with a single text input field and a button that says "Test banner". My goal is to inject a script that will manipulate the DOM of the given webpage and add a big red banner at the top, but I only want to inject it into the single url that I put in the text field.
Basically my options.html has a text input and a button. When the user enters a URL like google.com I want to open the page and inject into only that instance of the page. My issue is that
$('#start-button').button().click(function() {
var url = $('#url').value;
window.open(url)
});
My url successfully opens, but I "wish" I could "open and inject". Since I can't do that I've been relegated to trying to setup a background.js that listens for a window being opened, but that code keeps injecting into every tab with the url that I set (example. If I type google.com, then it will keep injecting into every google.com tab that I open).
So my question is... is there some kind of api available where I can do window.openAndInject(url)?
Note: I am very very new to this. Please excuse any noob mistakes I may have made.
I am struggling to access the DOM of the web page for my Chrome Extension.
In one extension I made, my extension parses the DOM from the content.js file without issue. This happens as the page loads. The user does not need to interact/open the extension at all, it just needs to be running in the backgorund.
Now I'm trying to trigger this from a button. This means the user will click the extension icon in the browser, and the popup.html will show some HTML (including the button).
This is where the problem lies for me. When I now try access the DOM (via click event of the button), it shows the popup.html's DOM, not the web page (The active tab).
So, a quick look through the docs (which I'm open to admit I struggle with) show that it could be a permissions issue. In my manifest.json file, I added
"permissions": [
"activeTab"
],
This didn't help :(
So in this new extension, I'm not using the background.js nor content.js .. I guess this is the problem, as the javascript I'm calling is embeded in the HTML pop up! This makes sense to me (as to the behaviour I'm getting).
How do I access the DOM of the active tab from the HTML pop up
The only way of accessing a page's DOM is by using a content script. Since you've set the activeTab permission you can use chrome.tabs.executeScript to inject a content script into the active tab by omitting the first parameter (the tabId).
Here is an example:
chrome.tabs.executeScript({ file: "content.js" });
I have had this same issue, I click on the button to open an popup, then how do I access the contents of the popup. Yes, you will need to use content scripts, but a trick I done to accomplish this, was when the popup is open, use window.name and get the name of that window. Then you can reference that popup window by var test = window.name('', 'name of that window'). Then you can reference the dom elements of the popup from test. Worked for me, let me know if I need to include some code to better explain.
I am working on a Chrome extension. What I would like to accomplish is redirecting hyperlinks that are opened in a new window or new tab. I've experimented with the code below and while this does redirect the tab it does not prevent the original page request from being submitted which is something I would also like to accomplish.
chrome.webNavigation.onCreatedNavigationTarget.addListener(function(details) {
chrome.tabs.update(details.tabId, {
url: 'http://www.google.com/'
});
});
I only want to redirect if the user opens a hyperlink in a new window (e.g. shift/ctrl+click, middle click, context menu, etc.). I do not want to redirect if the window, or tab, is being opened for a reason other than those.
Redirect new tabs/windows opened by only links, but not directly
Unfortunately, without a content script in every page, you can not differentiate between a user clicking a link and other reasons for opening a new tab or window, prior to the webRequest being transmitted.
The type of webNavigation that is causing the tab or window to be opened is clearly indicated by the value of the transitionType property, in the details supplied to a webNavigation.onCommitted listener. If it was from the user clicking a link, the transitionType property will have the value of link. If the request is from a link is not information that is normally available to the background page prior to the webNavigation.onCommitted event.
Unfortunately, for what you desire, the webNavigation.onCommitted event fires after the webRequest for the page's URL is complete. Thus, without some way to know earlier that the transition is the result of a user clicking a link (e.g. using a content script), you can't know that the current transition is the result of the user clicking a link in time to choose to redirect the webRequest for the main URL of the page.
What you can do is always redirect the initial request to about:blank. Then, once you get the webNavigation.onCommitted event, you can make the choice, based on the value of the transitionType property, to change the tab's URL to the redirect URL you ultimately have in mind, or change it back to the URL which was the original intended page. This process will result in the loss of the Referer header representing the page on which the link was clicked.
Obviously, you could use your ultimate destination instead of about:blank. This may be better, but will result in a webRequest to that URL even if the tab ultimately ends up being put back to the original destination URL.
Here is code that will do what is described above:
background.js
var tabsBlockedOnce = new Set();
var tabsRedirected = new Map();
chrome.webRequest.onBeforeRequest.addListener(function(details){
if(!tabsBlockedOnce.has(details.tabId)){
tabsBlockedOnce.add(details.tabId);
tabsRedirected.set(details.tabId,details.url);
//Redirect
return {redirectUrl:'about:blank'};
//Block
//return {cancel:true};
}
},{urls:['<all_urls>'],types:['main_frame']},['blocking']);
chrome.webNavigation.onCommitted.addListener(function(details){
if(tabsRedirected.has(details.tabId)){
//Default is to not redirect
let url = tabsRedirected.get(details.tabId);
tabsRedirected.delete(details.tabId);
if(details.transitionType === 'link'){
//It was a link, go to where we want to redirect.
url = 'http://www.google.com/';
}
//Send the tab where it is supposed to go
chrome.tabs.update(details.tabId,{url:url});
}
});
//Don't block the first request in any tab that already exists.
// This is of primary benefit when the extension is first installed/reloaded.
chrome.tabs.query({},function(tabs){
tabs.forEach(function(tab){
tabsBlockedOnce.add(tab.id);
});
});
manifest.json (partial):
"permissions": [
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"background": {
"scripts": ["background.js"]
}
With a content script in every page, you could do it directly
In order to perform this operation directly (i.e. not interfere with the original webRequest if the page is not ultimately going to be redirected), you have to know that the reason for the webRequest is that a link was clicked prior to the webRequest.onBeforeRequest event fires. To get this information to your background script in time, you would have to inject a content script in every page and runtime.sendMessage() a message to your background script that a link is in the process of being clicked.
Based on testing, such a message will get to the background script prior to the webRequest.onBeforeRequest firing. Being able to do this with a content script depends on the exact timing of the asynchronous communication between the content script sending a message with runtime.sendMessage() and when the runtime.onMessage event fires vs. when the webRequest.onBeforeRequest event fires. Testing indicates that the mousedown, mouseup and click events (click is not always fired for all mouse buttons) can send a message that the background script receives prior to the webRequest.onBeforeRequest event fires. This timing is not guaranteed, but appears to work.
From a User Experience point of view this is often a bad idea
What you desire to do usurps the user's choice to use a UI interaction to specifically open a link in a new tab or window. Unless I was specifically looking for this functionality, I would find this very annoying and, almost certainly, immediately uninstall the extension. Usurping the user's agency to control their machine is something that should be done only under very limited circumstances. Unless you are in a specialized environment, what you are proposing will be contrary to most user's expectations. In addition, it may break interactions with some websites.
I don't know this for sure, but wouldn't you have to cancel the native event in favor of what you want to do, similar to event.preventDeafult()?
I want to move my email from a somewhat unreliable provider (let's say X) to Gmail.
Unfortunately email provider doesn't allow folder export or direct IMAP link.
The only thing I can do is connect Gmail to X via POP3, so that anything in X's inbox gets copied to Gmail.
This I have set up, and it works, but of course POP3 only scans inbox.
I have thousands of emails in other folders than inbox, so I need to move them to inbox first. However, I can only move messages via X's web GUI, which only allows moving one page of messages per turn.
So I have to open Saved messages folder, click on "Select all", select "inbox" and click on "Move", then the page will reload and I need to do this again... hundreds of times.
I made a Javascript function (assume MoveToInbox()) which simulates these actions, and I opened page in Firefox and started Firefox Scratchpad. So, I can keep pressing Ctrl+R in Scratchpad, then wait for page reload, then press it again, which saves about 50% of time.
However, I am wondering, if I can somehow make Scratchpad work with that tab so that it waits for page reload, then executes script then waits again, eliminating all the manual repetitive tasks.
I thought I could somehow do it with window.addEventListener, but this object seems to get cleared on page reload, so is there something I could use instead?
My own quick answer is only by using a Firefox addon such as GreaseMonkey.
The solution will, of course, vary in different cases, but my own was this GreaseMonkey Javascript:
// the function to select all messages and programmatically click on
// move button:
function moveToInbox()
{
selectAllCheckbox=document.getElementById("messagesForm")[0];
mailboxSelector=document.getElementsByName('targetMailbox')[0];
selectAllCheckbox.click(); // click on "select all" checkbox
mailboxSelector.selectedIndex=1; //specify that we are moving to inbox
inx.mail.mailbox.mailboxTransfer(); // execute provider's function for moving mail.
}
// This gets executed on any page that matches URL specified in Greasemonkey script properties
// I have put this to execute, if the URL is for the folder I want to move messages from.
messageList=document.getElementById("messagesForm")[0];
// in my case, if there are no more messages to move, the form is not created at all, so
// I can check for its existance, to determine if I need to execute moving.
if (messageList == null)
{
return;
}
else
{
moveToInbox();
}
Using an iFrame
The first problem is that variables and functions get lost after reloading:
-Use an <iframe> with src = "X"
Now the Cross domain policy is causing troubles:
-Make the <iframe> on the same website as the src
Then, you can easily access and manipulate the website with iframeId.contentDocument
An example:
Navigate to google.com, use Inspect Element to add an iframe:
<iframe src="https://www.google.ae" id="someID"> </iframe>
Then, you can use JavaScript to do anything with the iframe:
someID.contentDocument.location.reload();
setTimeout('someID.contentDocument.getElementById('lst-ib').value="iframes rock"',1000); //You should use something better than setTimeout to wait for the website to load.