Adjusting the height of an IFRAME to match its content page's height can be a real drag when the containing and content pages are not from the same domain.
Do the Cross-Origin Resource Sharing (CORS) headers make it possible for the content page to authorize cross-domain access to its resources and thus allow its containing page to read its height? (or, alternatively, the containing page authorize the content page to announce its height?)
Or is CORS strictly an AJAX thing?
CORS doesn't let you do that, but you can use cross-document messaging to send strings between iframes and their parent windows even on different domains, and use that to communicate.
Most browsers support this although Internet Explorer's way differs from the others'.
Assuming what you want is to have the iframe announce to the parent page its desired height, you could put this in your iframe code (not tested):
var message = {
width: desiredWidth,
height: desiredHeight
};
window.parent.postMessage(JSON.stringify(message),'*');
And this in your containing page:
function onMessage (event) {
if (event.source != theIFrameElement.contentWindow) return;
var message = JSON.parse(event.data);
var desiredHeight = message.height;
var desiredWidth = message.width;
}
if (window.attachEvent)
window.attachEvent('onmessage', onMessage);
else if (window.addEventListener)
window.addEventListener('message', onMessage, false);
The attachEvent is for IE and addEventListener is for everyone else. You might want to check the target origin for security purposes, but that's the general idea.
EDIT: Browser support for Cross-document messaging (—fsb)
Related
I have a simple HTML page with an iframe. I set its src to another HTML
file and I can change the style of any chosen element at will using code
like this (a basic example):
function elementStyle()
{
var iFrame = document.getElementById( "iFrame" );
var element = iFrame.contentWindow.document.getElementsByTagName(
"table" )[0];
element.style.color = "#ff0000";
}
However the src of the iframe must be an external URL and cross-domain
restriction prevents me from accessing its elements. I have no control
over its content so I can't use postMessage() because I can't receive
any message posted.
Any ideas of a way to get round this?
Note: it must work for anyone with any browser so musn't use any special
methods (like jQuery, CORS etc).
Thanks
Related issues:
Server-side detection that a page is shown inside an IFrame
I find weird that we can't apparently know from the server side if whether the page is loaded through an iframe. Most answers say that it's only detectable from the browser, I just don't get why.
In the browser, we have access to document.referrer which clearly indicates the url we come from. There is something similar on the server side using req.headers.referer.
I just tested it with a local iframe and I got the following results:
referer http://localhost:8888/tests/chatbotIframeIntegration // The page containing the iframe
referer http://localhost:8888/chatbot // The page displayed within an iframe
referer undefined // seems to be undefined sometimes, maybe due to HMR?)
I can definitely detect the url the request comes from. So, if I know what url my app should be running into, I can definitely have some logic that figures out whether I'm calling my server from an external website, can't I?
Also, it's quite weird that the browser uses referrer and the server uses referer (one r)...
I've gained more experience through experimentation, so here is what I've learned so far.
As I thought, we can resolve the referrer through document.referrer (browser) and req.headers.referer (server).
So, it's possible to detect whether the current referrer is different than what's our hosting server, and in this case we know the query comes from an iframe.
It gets trickier when you want to know, from the server side, if a page within your site has been loaded through an iframe within that same site. In such case, there is no way to automatically detect whether we're running the page from an iframe or not.
For instance, if you have an iframe on page /index that loads /page2 page, then you can't know, from the server side if /page2 was loaded from the iframe (on /index) or from navigating to /page2.
And that's why people say there is no way to know, from the server side, if a page was loaded through an iframe. Because it's uncertain.
Now, my actual need was a little different. I needed to know if my /page2 was loaded from another domain that my own (cross domain), and that is fairly simple to know, because the referrer will be different that my own domain, both on the server side and browser side.
It got a bit more complex with my integration tests, because I had a /tests/iframeIntegration page that contains an iframe which loads another page /page2, from the same domain. (relative url)
The point was to test whether the iframe integration worked as expected, and because it was running on the same domain, I couldn't resolve whether I was loading it through an iframe.
For this particular case, I added a /page2?iframe=true in the url. It's the simplest workaround I've found that works universally (browser + server).
Here are a few utility scripts:
import { isBrowser } from '#unly/utils';
import includes from 'lodash.includes';
/**
* Resolves whether the current web page is running as an iframe from another page
*
* Iframes are only detectable on the client-side
* Also, using iframe=true as search parameter forces iframe mode, it's handy when using an iframe from the same domain
* (because same-domain iframes aren't detected when comparing window.parent and window.top since it's the same window)
*
* #return {boolean}
* #see https://stackoverflow.com/a/326076/2391795
*/
export const isRunningInIframe = (): boolean => {
if (isBrowser()) {
try {
return window.self !== window.top || includes(document.location.search, 'iframe=true');
} catch (e) {
return null; // Can't tell
}
} else {
return null; // Can't tell
}
};
/**
* Resolve the iframe's referrer (the url of the website the iframe was created)
*
* Helpful to know which of our customer use our app through an iframe, and analyse usage
* May not always work due to security concerns
*
* #return {string}
* #see https://stackoverflow.com/a/19438406/2391795
*/
export const getIframeReferrer = (): string => {
if (isRunningInIframe()) {
try {
return document.referrer || null;
} catch (e) {
return null;
}
} else {
return null;
}
};
I am trying to open some site in iFrame which opens as popup.
Some sites does not allow itself to open in iFrame (Frame Busting).
I have searched for this . i Have got some solution also like
$(window).bind('beforeunload', function (event) {
return 'Custom message.';
});
beforeunload not work for me, as it will run even when navigating within my site
and also I tried
// Event handler to catch execution of the busting script.
window.onbeforeunload = function () { prevent_bust++ };
// Continuously monitor whether busting script has fired.
setInterval(function () {
if (prevent_bust > 0) { // Yes: it has fired.
prevent_bust -= 2; // Avoid further action.
// Get a 'No Content' status which keeps us on the same page.
window.top.location.href = 'http://mysiteurl/#';
}
}, 1);
above is also not working, it will redirect to the url which is being opened in iFrame.
So Is there any solution to open site (having Frame Buster) in IFrame.
Regards,
Sagar Joshi
For IE use this in your frame security="restricted"
<iframe id="frame_id" name="frame_name" security="restricted" src="page.html">
</iframe>
Edit: I was having the same issue but I needed scripts etc to run in my frame so security restricted was not good. Try using sandbox="..."
allow-forms allows form submission
allow-popups allows popups
allow-pointer-lock allows pointer lock
allow-same-origin allows the document to maintain its origin
allow-scripts allows JavaScript execution, and also allows features to trigger automatically
allow-top-navigation allows the document to break out of the frame by navigating the top-level window
Top navigation is what you want to prevent, so leave that out and it will not be allowed. Anything left out will be blocked
ex.
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="http://www.example.com"</iframe>
I have a greasemonkey script that opens an iframe containing a form from a different sub-domain as the parent page.
I would like to refresh the parent page when the iframe refreshes after the form submission
I am at the point where I can execute a function when the iframe refreshes, but I cannot get that function to affect the parent document.
I understand this is due to browser security models, and I have been reading up on using postMessage to communicate between the two windows, but I cannot seem to figure out how to send a reload call to the parent with it.
Any advice on how to do that would be very helpful
thanks
Use:
window.parent.postMessage('Hello Parent Frame!', '*');
Note the '*' indicates "any origin". You should replace this with the target origin if possible.
In your parent frame you need:
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt)
{
if (evt.origin === 'http://my.iframe.org')
{
alert("got message: "+evt.data);
}
}
Replace "my.iframe.org" with the origin of your iFrame. (You can skip the origin verification, just be very careful what you do with the data you get).
How do I use the JavaScript DOM to apply onclick events to links inside of an iframe?
Here's what I'm trying that isn't working:
document.getElementById('myIframe').contentDocument.getElementsByTagName('a').onclick = function();
No errors seem to be thrown, and I have complete control of the stuff in the iframe.
Here is some code to test and see if I can at least count how many div's are in my iframe.
// access body
var docBody = document.getElementsByTagName("body")[0];
// create and load iframe element
var embed_results = document.createElement('iframe');
embed_results.id = "myIframe";
embed_results.setAttribute("src", "http://www.mysite.com/syndication/php/embed.php");
// append to body
docBody.appendChild(embed_results);
// count the divs in iframe and alert
alert(document.getElementById("myIframe").contentDocument.getElementsByTagName('div').length);
It is possible for an iFrame to source content from another website on a different domain.
Being able to access content on other domains would represent a security vulnerability to the user and so it is not possible to do this via Javascript.
For this reason, you can not attach events in your page to content within an iFrame.
getElementsByTagName returns a NodeCollection, so you have to iterate throgh this collection and add onclick handler to every node in that collection. The code below should work.
var links = document.getElementById('myIframe').contentDocument.getElementsByTagName('a');
for(var i=0;i<links.length;++i)links[i].onclick=function(){}
also make sure, you run this code after the frames' content is loaded
embed_results.onload=function(){
// your code
}