Bookmarklet, js injection and popup issue - javascript

I'm currently writing a bookmarklet that loads and executes a remote js file by appending a new <script> tag in the current window, like so :
javascript:(function() {
if(typeof __bml_main != "undefined") return __bml_main.init();
var s= document.createElement('script');
s.type= 'text/javascript';
s.src= 'http://127.0.0.1:8000/media/bookmarklet.js';
void(document.body.appendChild(s));
})();
My bookmarklet needs to perform some dom manipulations in order to extract data from the page being viewed, and then to open a new popup to list them.
The thing is : if I want to bypass pop-up blockers, I can't open my new window from the injected script. I need to open it right from the beginning in the bookmarklet code, and to access it later when needed.
I've tried to do somehting like this :
javascript:var my_popup = window.open('http://127.0.0.1:8000/resources/manage/new/', 'newResourcePopup',config='height=200,width=400,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,directories=no,status=no');
(function() {
// script injection (...)
})();
but if I then try to access my_popup from my remotely loaded script, most browsers will throw a security warning and won't let me access the Window object. This is understandable since the script is not from the same domain than the displayed page, but I'm kind of stuck...
A solution would be to use a div overlay, but I'd really prefer to open a window in this case.
Any hints ?

You could load the markup for the window as a string in your bookmarklet.js file, then (later) use window.open without a URL (or with "about:blank", I forget which is more cross-browser-compatible), and use my_popup.document.write to write the markup to the new window.
You may find that you can't open the window later, even without cross-domain issues, unless you're doing so in direct response to a user action — which is probably a good thing. :-)

Related

How to Get Access to Page's Script Context

My addon uses a content script to interact with the page. But it also needs access to the page's javascript so it can run one of the page's routines. So my content script needs access to the page's script context.
Here's what I mean.
Addon uses main.js which access content.js and uses messaging to communicate.
But the web-page (into which content.js is being injected) has it's own javascript. My content.js needs access to that context so it can fetch the values from variables there.
How can one get that?
I have been reading these mdn docs, but it seems like they are talking about an html page that you code yourself, like you would for a preferences page. But in my case I am working with an external website, not something coded just for the addon.
The approach listed on the MDN page also works for external pages, not just your own.
I.e. unsafeWindow.myPageVar will work.
This works:
var script = document.createElement("script");
script.innerHTML = "alert( myPageVar );";
document.body.appendChild( script );
Credit goes to this fellow.
I don't know whether this is the best way to do this, however. I hope that someone else more knowledgeable than me will answer.
Here's how to return a value:
var retval = unsafeWindow.SomePageFunction();
alert(retval);
It's called "unsafe" because you never know what about the page might be changed or might change. That's how it when the addon interacts with page scripts.

How to run Javascript in newly opened window?

Let's say I have the following code.
window.open(url, windowName, "height=500,width=500")
// This will open a new window with the url.
myFunction();
// Run this function on the newly opened window instead of
// the old one because I need to find a link on the new page.
Right now, myFunction() is getting stuck on the old window.
Update: The new url is the another domain.
Put your myFunction() in the script of the new window.
Then set the onLoad event of that window to run it.
You can get reference to your caller window's document from the new window by:
window.opener.document
There you go with enough links to do pretty much anything.
Update:
Your new window should be from the same domain. Otherwise its against the same origin policy of the browser.
Please see this question:
Ways to circumvent the same-origin policy
You have several options:
edit the source code for the webpage stored at url to include your own custom code that you want to run when the webpage opens. If you only want this code to run when the webpage opens from your popup, you could name the url something like "webpage.html?run_custom_code", then in webpage.html have javascript that only runs if window.location.href.indexOf('run_custom_code') > 0
you can open a webpage that's sole purpose is to run javascript: window.open('javascript:alert()'); although based on your edit this does not seem useful to you.
Use another language like PHP, where you can fetch the contents of another webpage with something like $html = file_get_contents($url);
perform an ajax request to the other url (if it resides on the same domain) and scrape the results to find your link.

Javascript get element from opened window

I need to open a new window and return an element contained in it.
Say we have page A and page B, I want:
open B from A
get the element interested in B
return that element to A
I tried to do so in this manner, but it doesn't work:
var newwindow = window.open("http://www.example.com");
var elem = newwindow.document.getElementById('my-id').value;
Where am I wrong? Has anyone some advice to me?
Since you are using an absolute URI, I'm going to assume that you are trying to grab data from a different website. You'll therefore be blocked by the same origin policy.
If that isn't the case, then you're probably hitting a race condition by trying to read the content of the document before it has finished loading.
It would be a lot easier to help if you provided the error messages that your browser is almost certainly logging to its JS console.
If the new window has the same protocol, domain and port, your code should work. If it's on another domain, you can't do this for security reasons.
If you control both pages, you could use window.postMessage.

javascript google chrome extension iframe cannot examine contentWindow

I am writing a Google Chrome extension. Now I need to examine the contents of an iframe but the content script seems unable to access this content even though the debugger can. The iframe contents are a list of messages I have previously sent to that site. If I put the following statement in the content script, it always returns null:
document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow.document;
But if I open the debugger and execute the same command from the command line, it returns "Document" with the appropriate contents. At first I thought it was because the frame wasn't finished loading so I found a snippet like this and tried to use it.
function wait4Iframe2Load() {
// Get a handle to the iframe element
//console.log('Checking for null myFrame');
var myFrame = document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow;
if (myFrame!=null)
{
console.log(myFrame);
// Check if loading is complete
if ( myFrame.document.readyState == 'complete' ) {
// The loading is complete, call the function we want executed once the iframe is loaded
console.log('Loading Complete');
//frameContent=document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow.document.getElementsByTagName('tbody')[0];
return;
}
else alert(" Frame is Not Loaded");
}
else myFrame = document.getElementById("td_messages_show").getElementsByTagName("iframe")[0].contentWindow;
// If we are here, it is not loaded. Set things up so we check the status again in 100 milliseconds
console.log('Waiting for frame to load...');
window.setTimeout('wait4Iframe2Load()', 100);
}
This simply returns null forever. But while this script is piling up console messages, I can open the debugger and execute the very same command line and it returns a document. Faced with this problem and researching internet answers, it seems it may be some deliberate kind of security issue. Whether it is or isn't, I need to examine the iframe contents and determine what I have written there previously so I can decide what to write there next.
Does anybody have an idea how to solve this problem?
The idea is to inject content script into this iframe and use it to get required information.
As I understand this frame has a specific url known upfront, so you can just inject the script through the manifest (use the all_frames option).
If for some reason you need to dynamically inject it, then there is:
chrome.tabs.executeScript(tabId, {allFrames: true});
It will be injected into both parent and iframe pages. Then inside injected content script you can check whether or not it is running inside the right iframe. For example your dynamically injected content script might look like this (if you inject it though the manifest url checking won't be needed):
if(window.location.href == "http://iframe.example.com/" && window != window.top) {
//we are in the right page that is embedded as iframe, do stuff
} else {
//do nothing
}
Excuse me, have you got solution, Jerome? I am having same problem as yours. But I can not make comment on your post. So please do not mind because this is a question...
Edited:
Finally I got it working. I don't understand while flag all_frames: true in manifest.json is not affected. I need to code as #serg's:
chrome.tabs.executeScript(tabId, {allFrames:true, file:"content_script.js"})
Thank you all, and could you please accept #serg's answer as the right one, Jerome? :-)
I created this library:
https://github.com/attachmentsme/Queuebert
to simplify the communication between browser tabs, the extension's background process, and iframes.
The use-case that I was running into was:
an action is taken in one iframe.
the results should be displayed in an alternate iframe.
Doing this can be a pain, hence the abstraction I built.

Open new page in the same broswer window without affecting the browser history

The question is for IE7 only, because location.replace(strURL) seems to work file in all other major browsers.
I try to execute some analytics js and then redirect the users to the location of a resource (usually doc or pdf) they want to download.
The user opens a page containing the js code.
After the download is tracked the broswer should load the resurouce url using the following code by REPLACING the current page entry in the history with the resource url:
if (IE) {
window.open(strURL,"_self", true); //doesn't work
//window.open(strURL,"_self",undefined, true); //doesn't work
return;
}
This code creates entry in the history for the redirecting page.
I have tried using iframe on the same page but IE will pop up a security warning if the file is a *.doc
Any ideas?
I'm not sure if there is a way to avoid this in IE7 or not. Perhaps a different approach is possible. Inject the analytics js into the current page before redirecting, thereby avoiding the need to load another page altogether. In this approach, you would create a new script tag and inject it into the head element. The script will execute when it loads, do your analytics and then trigger the redirect for download as the last step (for instance).
function redirectWithAnalytics() {
var s = document.createElement('script');
s.src = 'path/to/analytics.js';
s.type = 'text/javascript';
document.getElementsByTagName('HEAD')[0].appendChild(s);
}

Categories