I have an array of URL's and I want to create one iframe for each URL that I have.
But what I want is create and load the next iframe only when the previous was totally loaded.
This is the function that create the iframe:
function loadSubsequencePages(links){
var id = document.getElementsByTagName("iframe").length;
for(var i=0; i<links.length;i++){
var frame = document.createElement("iframe");
frame.setAttribute("id","frame"+id);
frame.setAttribute("src","about:blank");
document.getElementById('frames').appendChild(frame);
changeLoc(document.getElementById("frame"+id),links[i].href);
}
}
I want to move to the next i only when the actual iframe that I create was loaded.
this is the function that change the URL:
function changeLoc(frm,loc) {
frm.webNavigation.loadURI(loc,
frm.webNavigation.LOAD_FLAGS_NONE,
null, null, null
);
}
How can I do that?
That depends.
Do you have control over the pages shown in the IFRAMEs?
Are they
on the same domain as the hosting page?
There are four scenarios:
If they are on the same domain, you can access the content through
JavaScript.
If they are on the same domain, and you can modify the loaded
pages, you can tell the parent frame when the onload event
fires from the page loaded in the IFRAME.
If they are not on the same domain, and you can modify the loaded
page, security restrictions will block direct communication. But you
can ping a central repository on the server from the loaded page when
the onload event fires
If they are not on the same domain, and you can't modify the
loaded page... Well you're in trouble... :) You will not be able to
check when the pages have finished loading.... Well.. You could create some ugly
timer loading the pages at a set interval... But don't tell anybody I
told you so... ;)
If the iframes point to a URL that is another domain, all you can do is put an onload event on your iframe - that will tell you when the Iframe starts to load, but you'll never be able to tell when the load is complete because of the Same Origin Policy. The page inside is isolated from the hosting page in this situation.
If the iframes point to the same domain, you can insert some sort of document.ready code into the page that can then call a JavaScript function in the parent page announcing that it has finished loading.
Related
I am trying to run some javascript inside an iframe after it loads and am having trouble. I'm not sure if it means my concept of what is happening is wrong or if my code is just wrong.
What I want to do is load a javascript file in the iframe environment and then call a function. (the iframe contents are static web pages captured with singlefile and served from my server. I want to be able to pop up menus for the images in the iframe page). Is this possible, or is it blocked for security considerations? I can get the contentDocument from the iframe and see what is in it but not make any changes to it. Adding a load event listener to the iframe runs in the top-level DOM, not the iframe.
An ugly workaround would be to add a line loading the script to each of my served html files, but I'm reluctant to do that since it seems kind of fragile. Is that my only option?
you can select the iframe element and access its internal window object.
to do this first assign an id to your iframe element
<iframe id="chosen-iframe" ...></iframe>
and to access the window use the following
const iframe = document.getElementById('chosen-iframe');
const iFrameWindowElement = iframe.contentWindow;
and with access to the window, you can create a script tag that contains the script you want to inject inside the iframe
var injectedScript = iFrameWindowElement.document.createElement("script");
injectedScript.append(...);
iFrameWindowElement.document.documentElement.appendChild(script);
I'm creating a single-page web app that has 3 parts:
A header
A sidebar for navigation
An i-frame to show the main page content
The header and sidebar should never reload after the first page load - only the i-frame. I'm using the History API (i.e. pushstate) to handle history and navigation.
The problem I'm having is if someone types in a url directly to any page in the site, I want to load the header and sidebar and then load the page they went to in the i-frame. If they're already on the page and they click a link to a different page, I only want it to load the new page in the i-frame. I'd like to do this without messing up the navigation history as well.
How do I detect this and load the content appropriately?
In the iframe you would use a little piece of Javascript looking at window.parent and window.top like this:
Javascript in iframe
if (window.parent == window.top) {
// user loaded the iframe, go to parent
window.location = "<your parent url>" + "?iframe=" + window.location;
}
Then in the parent load the iframe that is indicated by $_GET['inframe']:
PHP in parent
if (isset($_GET['inframe']) {
loadIframe($_GET['inframe']);
}
where I made up a loadIframe() function, since you didn't provide any code, so you have to replace that with your own.
For security reasons you may want to filter the input with filter_input():
PHP in parent
if (isset($_GET['inframe']) {
loadIframe(filter_input(INPUT_GET, 'inframe'], FILTER_VALIDATE_URL);
}
And perform further checks. This way you can prevent people from using the iframe parameter to inject something malicious in your code, or from loading just any iframe they please.
Instead of an iframe you could use AJAX to load content, and avoid this problem altogether. An iframe however allows for a more traditional way of loading content.
Since there is no way to prevent an iframe from redirecting the top frame besides sandboxing which prevents other features required for viewability tracking I would like to track redirects. Since one site can have more than one iframe, it could be any of these.
Is there any way to track/find out which one (specific iframe) caused the top frame redirect?
Here is a sandbox (use browser console and enable preserve log):
Note the iframe content is usually cross domain. For ease of use its within the sandox.
We can access to the iframe content with somethig like iframe.contentWindow.document but this is possible if we observe Same-origin policy.
Another approach could be setting a Content-Security-Policy header like:
<meta http-equiv="Content-Security-Policy" content="frame-src http://example.com">
This header in the parent page prevents to load sites different to http://example.com in frames, There is also a way to report the refuse behavior sending a post but unfortunately can't be setting with <meta> tag (it's only server side). With this approach we have to perform a white list, so I think maybe it's not useful in this case. But, if the white list is given the first time, is possible to set all sites available, so when the iframe redirect, browser will refuse to load it.
If it's not the case of same-origin and the possibility of performing a white list, then I think the better we can do is calling iframe onunload event, unfortunately this event are going to be fired also when iframe page reloads not only on redirection. I think it's the closest approach. To achieve that, this code works.
var srcs = ["iframe2.html","iframe.html","iframe2.html"];
for (let i = 0; i < srcs.length; i++) {
var iframe = document.createElement('iframe');
iframe.src = srcs[i];
iframe.name = "i"+i;
document.body.appendChild(iframe);
window["i"+i].onunload = function(){console.log("change "+i)}
}
Of course onunload is fired the first time, when all iframes load, so redirections are 2th 3th and so on. But we could exclude that first case.
Here a full example https://codesandbox.io/s/o16yk7mqy , I've created iframe3.html that doesn't refresh neither reload to show clearly the point. Also I've created a simple List of redirect or reload iframes.
UPDATE
As I understand now, what you want is to set iframes with sandbox property and whitelist all what you want but without allow-top-navigation, something like:
<iframe src="iframe.html" sandbox="allow-script allow-forms allow-popups allow-pointer-lock allow-same-origin"></iframe>
This Example doesn't allow allow-top-navigation https://codesandbox.io/s/lpmv6wr6y9
This Example here https://codesandbox.io/s/4x8v1mojq7 allow allow-top-navigation but codesandbox prevents the frame to redirect so if we try https://4x8v1mojq7.codesandbox.io/ that is the url created by codesandbox, we could see the top frame reload.
As I said in comments, at least Chrome 64.0.3282.167, when we delegate all but allow-top-navigation when the iframe attempt to redirect top frame, it throw an exception. The behavior is different in Firefox (at least 58.0.2). Firefox deny top navigation but continues with the code.
So, as conclusion the best approach in my opinion is or a combination of sanbox and onunload or just onunload. Of course, if it could be possible, Content-Security-Policy is the safest and more flexible way. It depends of the implementation. It's almost impossible I think not to involve server side code to perform a perfect solution. There are white list to check, like this API https://developers.google.com/safe-browsing/v4/ and there are black list to check, look at this post https://security.stackexchange.com/questions/32058/looking-for-url-blacklists-of-malicious-websites .
If you have control over all your frames you can implement interaction between frames with postMessage. Flow:
Frame want to execute redirect - it sends a message to parent frame with redirect request.
Parent frame executing redirect and know which frame caused a redirect.
Parent:
window.addEventListener("message", (event) => {
// show message source (your frame)
console.log(event.source);
const message = event.data;
console.log(`Frame ID: ${message.frameId}`);
if(message.messageType === "redirect") {
window.location.href = message.redirectUrl;
}
});
Child frame:
function redirect(url) {
var message = {
messageType: "redirect",
frameId: "frame1"
redirectUrl: url
}
window.parent.postMessage(message, "*");
}
You can show a dialog box before redirecting to another domain/application and then the user can decide - to stay or leave the current application. You can also track the current target (i.e. iframe in your case).
window.onbeforeunload = function (e) {
console.log(e.currentTarget.location.href);
return 'Stop redirection. Show dialog box.';
};
From the individual iframes, can you set a cookie when the redirect happens? Say it happened from iframe1, you may set a cookie like
document.trackFrame = "FrameName=iframe1";
And once the redirect completes, can you try reading the cookie and there by determine which iframe caused the re-direct?
I want to track with a google analytics event the click on a href that is inside a iframe on my page. The iframe is in the same domain.
Is it possible? how?
The iframe is insert dynamically on the page after it loads. Is it important for this code to be put after the iframe?
If the iframe is on your domain the contents of the iframe are propably under your control ( if it wasn't you wouldn't have any business tracking the frame). So you can simply install the Google Analytics tracking code in you iframe'd document (which you want to do anyway, after all a framed page is not very different from any other page on your website an you'll want to know how often it was called). So while you can access the parent frame from your (same origin) iframe (calling window.parent) it is not necessary or recommendable.
If the iframe is the same domain, you can (from your main window) wait for the iframe to load and then install an event listener to handle the click on a particular link.
The code you will need is:
Code to wait for the iframe content to load.
Code to find the relevant link in the iframe
Code to install the event listener
Code to handler the click event
I have 2 questions :
How do I know that the contents of the frame ready/loaded (as $(document.ready()))?
How do I know that the popup (window.open()) contents ready/loaded (as $(document.ready()))?
Google said that could help $("iframe").load(), but I did not understand how
DEMO — iframe
The problem with using load() is the iframe may have already loaded before the jQuery has run, thus not triggering the function. One way around this would be to initially load nothing in the iframe (about:blank), then using jQuery to change the src attribute to get the iframe to point to the desired location.
DEMO — window.open (Disable your popup blocker for this demo.)
I'm not sure whether ready() can be used cross-domain. When loading a popup/iframe on the same domain, a script on the child page can be used to report back to the parent window that it is "ready".
The load callback will be called when the iFrame will be load :
$("#iframe-id").load(function(){
//The iFrame content is loaded
})