Cross domain iframe src changes - javascript

I have an application which contains an iframe. I can modify the contents of the iframe, but not the whole page itself, e.g.:
<html><head></head>
<body>
<iframe>
<!-- my code -->
</iframe>
</body></html>
I have a requirement in which I need to change contents of the iframe to a different page (possibly on a different domain) and go back. Currently I do it like this:
The first page (it is inside the iframe executionPanelApplications):
<html>
<head>
<script type="text/javascript">
function replaceIFrameUrl() {
var doSubmit = "<c:out value='${param.doSubmit}'/>";
if (doSubmit == 1) {
document.forms['testForm'].submit();
}
else {
var adfUrl = "<fuego:fieldValue att='instJs.adfUrl' onlyValue='true'/>";
var bpmSrc = parent.document.getElementById('executionPanelApplications').src;
var bpmSrcParams = bpmSrc.split('&');
var activityId = (bpmSrcParams[1].split('='))[1];
var url = adfUrl +"&actionType=0&activityId="+activityId;
parent.document.getElementById('executionPanelApplications').src = url;
}
};
</script>
</head>
<body onload="replaceIFrameUrl();">
<form method="post" id="testForm" name="testForm" />
</body>
</html>
The second page (it should be inside the iframe executionPanelApplications as well):
<script>
function leave(e) {
var iframe = parent.parent.document.getElementById("executionPanelApplications");
iframe.src = url;
};
</script>
If both sites are in localhost it works like a charm. Unfortunatelly if they are in different domains - the second page is opened in a new window. Tested in ie 8. As i said - i can't change the contents of the page that contains the iframe. I can only work from inside the iframe. I need this to work only in ie.
Any ideas?

I would not use iframes, because there are different security restrictions (cross domain communication)
But I think, this one can help you: http://softwareas.com/cross-domain-communication-with-iframes

Related

Calling js function from an iframe when user scrolls to the iframe or when the iframe is in viewport

My website provides iframe code which is put in some other websites.
For simplicity lets say my domain i.e the source of the iframe is www.abc.com and my client who uses my iframe code has domain www.xyz.com.
In my iframe website I try to access geoLocation of user using javascript.
When www.xyz.com is browsed on mobile, www.abc.com (in iframe) puts a confirmation box to allow or deny the access for geoLocation.
Now my issue is:-
I want to show the confirmation box only when the iframe is in the viewable area of the browser. And I want to do it without asking my clients to put any more js code in their website. It should all happen from my iframe source.
I tried the following, but visibilityChanged() gets fired only when we change the browser tab or minimize or maximize the browser...
Sample code. a.html
<!DOCTYPE html>
<html>
<head>
<script>
function onLoad() {
console.log('onload:', (document.hidden));
document.addEventListener("webkitvisibilitychange", visibilityChanged);
}
function visibilityChanged() {
console.log('visibilityChanged: ',arguments);
}
</script>
</head>
<body onload="onLoad()">
test
</body>
</html>
b.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<iframe style="border:1px solid red; width:200px;height:200px;" src="a.html"/>
</body>
</html>
The new PageVisibility API, which should be widely supported on mobile, looks much more promising:
Broad support: http://caniuse.com/#feat=pagevisibility
Spec: http://www.w3.org/TR/page-visibility/
Code snippet from the spec (above):
var timer = 0;
var PERIOD_VISIBLE = 1000;
var PERIOD_NOT_VISIBLE = 60000;
function onLoad() {
timer = setInterval(checkEmail, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
if(document.addEventListener) document.addEventListener("visibilitychange", visibilityChanged);
}
function visibilityChanged() {
clearTimeout(timer);
timer = setInterval(checkEmail, (document.hidden) ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
}
function checkEmail() {
// Check server for new messages
}

Adding a variable to iframe's global scope

My index html:
<html>
<head>
<title>index</title>
<script src="jquery.js"></script>
</head>
<body>
<h1>Index</h1>
<hr/>
<iframe id="frame"></iframe>
<hr/>
<button id="btn">Click</button>
<script>
$(function(){
window.api = {
fun: function(){alert('index api')}
};
var frame = document.getElementById('frame');
frame.src = 'frame.html';
});
$('#btn').click(function(){
$('#frame').contents().find('body').css('backgroundColor', 'red');
$('#frame').contents().find('#btn').text('lol');
});
</script>
</body>
</html>
In the loaded frame.html the javascript can acces the api object via parent.api.
Is it possible to add an api object to frame.html window, so it is accessible via window.api there? (and not parent.api) (consider same origin and differnet origins)?
The above code does work (e.g. the #button changing the background and label), but I assume it's because all those documents are on my pc (same origin). Am I right?
Assuming you're not running into the same origin policy
var frame = document.getElementById('frame'); // get the frame
frame.addEventListener('load', function () { // only access when loaded
var win = frame.contentWindow; // get reference to iframe's `window`
win['foo'] = 'bar'; // set global (within iframe)
});
frame.src = 'frame.html'; // load up page in iframe
If the contents are on a different domain, it's not guaranteed that you will be able to access the <iframe>'s Window even with CORS set up.
The way functions and scope work means they are a bit more difficult to do in the right context, you'd have to either make them generic so it doesn't care or use new win.Function

changing iframe url changes parent window url

i'm using following page to display content of a url in a iframe and changing it based on input value .
<html>
<head>
<script type="text/javascript">
function changeUrl()
{
var url=document.getElementById('browseurl').value;
if(url!="")
{
if(url.indexOf("http")==-1)
{
url="http://"+url;
}
document.getElementById('browserWnd').src=url;
}
}
</script>
</head>
<body>
<div >
<span>Url</span>
<input id="browseurl" name="browseurl" type='textbox' />
<input id="browse" type='button' value="changeurl" onclick="changeUrl()" />
</div>
<iframe id="browserWnd" src="http://www.coolmath.com/" height="700" width="625"></iframe>
</div>
</body>
</html>
my problem is browsing some inner pages of an url loaded in iframe changes the parent window url instead of loading in iframe ...
for ex http://www.coolmath.com/ load in iframe but while browsing some links loads the entire page in parent window.
From www.coolmath.com:
if (window.self != window.top) ...
meaning the site activly escapes being framed.
You may notice that even something like this <iframe src='http://www.coolmath-games.com/0-fraction-splat/index.html'></iframe> results in the same. This is a technique called frame-busting. It's in their page's code:
<script>
<!-- Hide Script
if (top.location != self.location) {
top.location = self.location
}
//End Hide Script-->
</script>
If you have a server, that can respond with a HTTP/1.1 204 No Content header, you may be able to "deactivate" this frame buster as described here.

IE Issue: Submitting form to an iframe using javascript

I was trying to create an iframe element using javascript, like so:
var iframe = document.createElement('iframe');
iframe.setAttribute('name', 'frame_x');
However, when I tried submitting a form using the newly-created iframe as target, IE opens up a new window, instead of using the iframe.
form.setAttribute('target', 'frame_x');
form.submit();
This works perfectly in Firefox. Also, the iframe gets created, but is not used.
You've hit a bug in Internet Explorer.
You CAN NOT set the name attribute of ANY element in IE using the standard DOM Method .setAttribute('name', value);
In IE (before version 8 running in IE8 standards mode) this method will not work to set the name attribute.
You need to use one of the following:
//A (any browser)
var iframe = document.createElement('iframe');
iframe.name = 'frame_x';
//B (only in IE)
var iframe = document.createElement('<iframe name="frame_x"/>');
//C (use a JS library that fixes the bug (e.g. jQuery))
var iframe = $('<iframe name="frame_x"></iframe>');
//D (using jQuery to set the attribute on an existing element)
$('iframe:first').attr('name','frame_x');
Welcome to SO.
One issue I saw in your code is that you're never actually displaying the iframe. In order for it to appear on the page, you have to insert it into your document. In my example, I create a <span> tag to act as the slot where the iframe will get inserted.
See if this does what you're looking for.
<!-- http://stackoverflow.com/questions/2181385/ie-issue-submitting-form-to-an-iframe-using-javascript -->
<html>
<head>
<script type="text/javascript">
function submitFormToIFrame(){
var form=document.getElementById('myform');
form.setAttribute('target', 'frame_x');
form.submit();
}
</script>
</head>
<body>
<h1>Hello Erwin!</h1>
<form id="myform" name="myform" action="result.html">
<input type="button" value="Submit the Form" onClick="submitFormToIFrame();">
</form>
<span id="iframeSlot">
<script type="text/javascript">
var iframe = document.createElement('iframe');
iframe.setAttribute('name', 'frame_x');
document.getElementById('iframeSlot').appendChild(iframe);
</script>
</span>
</body>
</html>
UPDATE:
I found that this solution is only working in Firefox. So I did some experimenting. It seems that if you define the iframe in the html (instead of generating it via JS/DOM) then it works. Here is the version that works with IE and Firefox:
<html>
<head>
<script type="text/javascript">
function submitFormToIFrame(){
//IE
if( document.myform ){
document.myform.setAttribute('target','frame_x');
document.myform.submit();
//FF
} else {
var form=document.getElementById('myform');
form.setAttribute('target', 'frame_x');
form.submit();
}
}
</script>
</head>
<body>
<h1>Hello Erwin!</h1>
<form id="myform" name="myform" action="result.html" target="">
<input type="button" value="Submit the Form" onClick="submitFormToIFrame();">
</form>
<span id="iframeSlot">
<iframe name="frame_x">
</iframe>
</span>
</body>
</html>
function sendForm(idform){
var nfi = "RunF"+tagRandom();
$("body").append("<iframe name=\""+nfi+"\" id=\""+nfi+"\" class=\"runAgents\" src=\"#\"></iframe>");
$("#"+idform).attr("target",nfi);
$("#"+idform).submit();
}
To continue #scunliffe’s answer, if using Prototype.js:
var iframe = Element('iframe', {name: 'frame_x'});
which works because this helper function detects HAS_EXTENDED_CREATE_ELEMENT_SYNTAX for IE, working around the .name = … bug.

Write elements into a child iframe using Javascript or jQuery

I have something like this:
<!doctype html>
<html>
<body>
<iframe id="someFrame"></iframe>
</body>
</html>
And I would like to use jQuery to write elements such that the full equivalent HTML would be like this:
<!doctype html>
<html>
<body>
<iframe id="someFrame">
<!-- inside the iframe's content -->
<!-- <html><body> -->
<div>A</div>
<div>B</div>
<div>C</div>
<!-- </body></html> -->
</iframe>
</body>
</html>
Alternatively, any plain-old-Javascript would be fine.
Thanks.
Edit: After a little more research, it seems I am looking for an IE-equivalent of the contentDocument property of an iframe. "contentDocument" is a W3C standard which FF supports, but IE does not. (surprise surprise)
You can do both, you just have to target differently:
var ifrm = document.getElementById('myIframe');
ifrm = ifrm.contentWindow || ifrm.contentDocument.document || ifrm.contentDocument;
ifrm.document.open();
ifrm.document.write('Hello World!');
ifrm.document.close();
After some research, and a corroborating answer from Mike, I've found this is a solution:
var d = $("#someFrame")[0].contentWindow.document; // contentWindow works in IE7 and FF
d.open(); d.close(); // must open and close document object to start using it!
// now start doing normal jQuery:
$("body", d).append("<div>A</div><div>B</div><div>C</div>");
There are two reliable methods to access the document element inside an iframe:
1. The window.frames property:
var iframeDocument = window.frames['iframeName'].document; // or // var iframeDocument = window.frames[iframeIndex].document;
Demo
2. The contentDocument property:
var iframeDocument = document.getElementById('iframeID').contentDocument; // or // var iframeDocument = document.getElementById('iframeID').contentWindow.document;
Demo
I am going out on a limb here and suggest that the answers proposed so far are not possible.
If this iframe actually has a src="somepage.html" (which you ought to have indicated, and if not, what is the point of using iframe?), then I do not think Jquery can directly manipulate html across frames in all browsers. Based on my experience with this kind of thing, the containing page cannot directly call functions from or make any sort of Javascript contact with the iframe page.
Your "somepage.html" (the page that loads in the iframe) needs to do two things:
Pass some kind of object to the containing page that can be used as a bridge
Have a function to set the HTML as you desired
So for example, somepage.html might look like this:
<!doctype html>
<html>
<head>
<script src="jquery.js">
</script>
<script language=JavaScript>
<!--//
var bridge={
setHtml:function(htm) {
document.body.innerHTML=htm;
}
}
$(function() { parent.setBridge(bridge); });
//--></script>
</head>
<body></body>
</html>
and the containing page might look like this:
<!doctype html>
<html>
<head>
<script src="jquery.js">
</script>
<script language=JavaScript>
<!--//
var bridge;
var setBridge=function(br) {
bridge=br;
bridge.setHtml("<div>A</div><div>B</div><div>C</div>");
}
//-->
</script>
</head>
<body><iframe src="somepage.html"></iframe></body>
</html>
This may appear a bit convoluted but it can be adapted in a number of directions and should work in at least IE, FF, Chrome, and probably Safari and Opera...
I have found this to be cross-browser compatible... a little crossing of previous answers and a bit of trial & error of my own. :)
I'm using this for a download of a report, or, if an error (message) occurs, it's displayed in the iFrame. Most of the users will probably have the iFrame hidden, I'm using it multi-functional.
The thing is I have to clear the contents of the iFrame every time I click the report download button - the user can change parameters and it happens there are no results which then is displayed in the iFrame as a message. If there are results, the iFrame remains empty - because the code below has cleared it and the window.open(...) method generates a Content-Disposition: attachment;filename=... document.
var $frm = $("#reportIFrame");
var $doc = $frm[0].contentWindow ? $frm[0].contentWindow.document : $frm[0].contentDocument;
var $body = $($doc.body);
$body.html(''); // clear iFrame contents <- I'm using this...
$body.append('<i>Writing into the iFrame...</i>'); // use this to write something into the iFrame
window.open(Module.PATH + 'php/getReport.php' + Report.queryData, 'reportIFrame');
I do not have a browser that supports contentDocument but I've coded it this way so I'm leaving it. Maybe someone has older browsers and can post compatibility confirmation/issues?

Categories

Resources