Working of an iframe - javascript

Here is a snippet of code that uses a script to populate the contents of an iframe:
<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(function() {
$('iframe').contents().find('body').html('<script>console.log($("div"))<\/script>');
});
</script>
</head>
<body>
<div>Test</div>
<iframe />
</body>
</html>
When executed we see that the iframe has access to the parent's DOM and we see the div being selected by the jQuery selector. The iframe does not have jQuery included but it can access the jQuery object of the parent.
However if we write the same thing via an iframe src inclusion, the behavior is different:
test.html:
<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
</head>
<body>
<div>Test</div>
<iframe src="another.html">
</body>
</html>
another.html:
<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(function() {
console.log($('div'));
});
</script>
</head>
<body>
</body>
</html>
We now see that the page does not list any divs. Further, if we don't include the jQuery js in the child page, it would throw an error.
Note that both pages are in the same domain, so we don't have same-origin policy issues.
My questions are:
Why is the behavior different for the 2 - a. manipulating the iframe DOM from the parent and b. including the iframe content via a src?
Is there a way to make the parent have access to the child and NOT vice-versa?

So the first bit of code gives 1 and the second bit of code gives 0?
That seems correct.
In the first example $ is bound to the parent frame. In the second example, since you have a new instance of jQuery it's bound to the iframe.
In:
$(document).ready(function() {
$('iframe').contents().find('body').html('<script>console.log($("div"))<\/script>');
});
jQuery's html function will do an eval on the script-part of the inserted HTML. That eval will run in the scope of the parent so it uses the parent instance of $.
If you just moved the script to the iframe it will fail because it doesn't have access to $.

Related

Is it possible to retrieve the *full* HTML page source of an iframe with Javascript?

I am trying to figure out how to retrieve the full (that means all data) HTML page source from an <iframe> whose src is from the same originating domain as the page that it is embedded on. I want the exact source code at any given time, which could be dynamic due to Javascript or php generating the <iframe> html output. This means AJAX calls like $.get() will not work for me as the page could have been modified via Javascript or generated uniquely based on the request time or mt_rand() in php. I have not been able to retrieve the exact <!DOCTYPE> declaration from my <iframe>.
I have been experimenting around and searching through Stack Overflow and have not found a solution that retrieves all of the page source including the <!DOCTYPE> declaration.
One of the answers in How do I get the entire page's HTML with jQuery? suggests that in order to retrieve the <!DOCTYPE> information, you need to construct this declaration manually, by retrieving the <iframe>'s document.doctype property and then adding all of the attributes to the <!DOCTYPE> declaration yourself. Is this really the only way to retrieve this information from the <iframe>'s HTML page source?
Here are some notable Stack Overflow posts that I have looked through and that this is not a duplicate of:
Javascript: Get current page CURRENT source
Get selected element's outer HTML
https://stackoverflow.com/questions/4612143/how-to-get-page-source-using-jquery
How do I get the entire page's HTML with jQuery?
Jquery: get all html source of a page but excluding some #ids
jQuery: Get HTML including the selector?
Here is some of my local test code that illustrates my best attempt so far, which only retrieves the data within and including the <iframe>'s <html> tag:
main.html
<html>
<head>
<title>Testing with iframe</title>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function test() {
var doc = document.getElementById('iframe-source').contentWindow.document;
var html = $('html', doc).clone().wrap('<p>').parent().html();
$('#output').val(html);
}
</script>
</head>
<body>
<textarea id="output"></textarea>
<iframe id="iframe-source" src="iframe.html" onload="javascript:test()"></iframe>
</body>
</html>
iframe.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html class="html-tag-class">
<head class="head-tag-class">
<title>iframe Testing</title>
</head>
<body class="body-tag-class">
<h2>Testing header tag</h2>
<p>This is <strong>very</strong> exciting</p>
</body>
</html>
And here is a screenshot of these files run together in Google Chrome version 27.0.1453.110 m:
Summary
As you can see, Google Chrome's Inspect element shows that within the <iframe> the <!DOCTYPE> declaration is present, so how can I retrieve this data with the page source? This question also applies to any other declarations or other tags that are not contained within the <html> tags.
Any help or advice on retrieving this full page source code via Javascript would be greatly appreciated.
Here is a way to build it from the doctype, seems to work for html 4 and 5, I didn't test for stuff like svg.
<html>
<head>
<title>Testing with iframe</title>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
function test() {
var d = document.getElementById('iframe-source').contentWindow.document;
var t = d.docType;
$('#output').val(
"<!DOCTYPE "+t.name+
(t.publicId? (" PUBLIC "+JSON.stringify(t.publicId)+" ") : "")+
(t.systemId? JSON.stringify(t.systemId) :"")+
">\n" + d.documentElement.outerHTML );
}
</script>
</head>
<body>
<textarea id="output"></textarea>
<iframe id="iframe-source" src="iframe.html" onload="test()"></iframe>
</body>
</html>
this also uses HTML.outerHTML to make sure you get any attribs on the documentElement.

JavaScript code place in the header

I am not clear why its not working the javascript code when I add it to the header section as follows.
We can place a javascript code within the body as follows
<html>
<head>
<title> Simple Test </title>
</head>
<body>
<div id="mydiv"> This is the div content </div>
<script type="text/javascript" >
document.getElementById("mydiv").innerHTML=Date();
</script>
</body>
</html>
But when I place the same JavaScript code in the header section it doesn't work.
<html>
<head>
<title> Simple Test </title>
<script type="text/javascript" >
document.getElementById("mydiv").innerHTML=Date();
</script>
</head>
Can Someone please explain the issue. I know I can Write a JavaScript function in header and call it in an event. But can't we Use in this way. If Can't why.
<html>
<head>
<title> Simple Test </title>
<script type="text/javascript" >
window.onload= function (){document.getElementById("mydiv").innerHTML=Date();}
</script>
</head>
I think above code will help you to solve your problem. You can try this one.
because when the page is loaded, by the time the browser gets to that <script> element, the #mydiv element has not yet been created.
either use an "onload" event, or put your scripts at the bottom of the page.
It's because the page is being rendered in the order it's read. Therefore when the script in the header is evaluated the rest of the page hasn't been rendered yet (ie the myDiv element hasn't been created).
When you create an event handler in the head that works fine - the handler is set up before the rest of the page is loaded but the event can't happen until the element exists.
When you put it in the <head>, it runs before the <body> exists.
this is because of the page rendering order.you can access elements before it has been created. if you can, try to put all JavaScript code end of the page(before closing body tag). it will save your page load time. if you cannot put it in the bottom, put the code inside onload event.

javascript tag trigger - code position on page

i use that tag to alert me when a tag has been shows up
<html>
<head>
</head>
<body>
<script type="text/javascript">
document.getElementsByTagName('iframe')[0].onload = function() {
alert('loaded');
}
</script>
<iframe></iframe>
</body>
</html>
strange , since this code working :
<html>
<head>
</head>
<body>
<iframe></iframe>
<script type="text/javascript">
document.getElementsByTagName('iframe')[0].onload = function() {
alert('loaded');
}
</script>
</body>
</html>
why the Js need to under the tag to work?
what's the problem here?
Because the code in a script tag is executed immediately. And in the first example the iframe doesn't exist at that time. But what you can do is to wrap you code into an onload (for the main page) event. E.g.:
window.onload = function() {
//your code
}
Then it doesn't matter where the code is placed.
Iframe tag does not exist at the moment you are trying to access it.
You may check that by simply alerting array length, like
alert(document.getElementsByTagName('iframe'));
Have you thought about executing your javascript after the page is loaded? You may use some frameworks like jQuery to facilitate crossbrowser issues. Or just put all your javascript code to the very bottom of body.

JavaScript: Why is it so with windows.parent?

Why is it so that when you use window.parent.showMessage("Video Is OK"); inside a .js file you've included on a page, it won't work, but only if it's on the page itself..?
Can you fix this?
There are two scenarios that I can think of where you'd want to use window.parent. The first is when you have a window open another window using window.open. The other is where the first window uses an iframe to load a page. In the former case, it appears as though you actually want to use window.opener, as ukostin has said. In the latter case, window.parent works fine. Both methods work properly whether the code is inline or loaded from an external JS file. Here are some tests:
POPUP
parentWindow.htm:
<html>
<head>
<script>function showMsg(msg){alert(msg);}</script>
<body>
Open
</body>
</html>
externalWindow.js:
function showMsgExternal(msg){window.opener.showMsg(msg);}
childWindow.htm:
<html>
<head>
<script>function showMsgInline(msg){window.opener.showMsg(msg);}</script>
<script src="externalWindow.js"></script>
</head>
<body>
Inline
External
</body>
</html>
IFRAME
parentFrame.htm:
<html>
<head>
<script>function showMsg(msg){alert(msg);}</script>
</head>
<body>
<iframe src="childFrame.htm" width="300" height="100"></iframe>
</body>
</html>
externalFrame.js:
function showMsgExternal(msg){window.parent.showMsg(msg);}
childFrame.htm:
<html>
<head>
<script>function showMsgInline(msg){window.parent.showMsg(msg);}</script>
<script src="externalFrame.js"></script>
</head>
<body>
Inline
External
</body>
</html>
Try to use window.opener as link to the parent window.

Accessing a javascript function in a nested iframe in IE

I currently have a page structure that consists of a page(Parent) that includes an iframe(iframe0) and inside that iframe I have another iframe(iframe1). In iframe1 I have a javascript function that I am trying to call from Parent. In Firefox/Chrome/Safari I am able to call this function with the following code:
frames["iframe0"]["iframe1"].functionName();
However, in Internet Explorer the above code does not work and it returns the error "Object doesn't support this property or method". I have tried some other ways to access the method with them all returning the same error.
window.frames.iframe0[iframe1].functionName();
window.iframe0.iframe1.functionName();
window.frames.iframe0.frames.iframe1.functionName();
I even tried calling a function in iframe0 that called the function in iframe1 and that didn't even work.
Anyone have any idea on how to access a javascript function that is nested in an iframe that is 2 levels deep?
Thanks.
Update:
After looking into the problem further, I have found that the problem I am dealing with is not related what I have asked. The answer ylebre gave below answers the question I have asked, and there for will me marked as the answer. I will probably start another question describing my problem in more detail.
I've provided an example using 3 HTML files. The outermost is test.html which has an iframe containing iframe1.html. In turn, iframe1.html contains an iframe containing iframe2.html. I'm hoping this is the kind of setup that you have in mind.
Basicly, you can call the iframe function using iframe.contentWindow.myfunc();
Using contentWindow.document you can then access the second level iframe.
The example function 'doit()' calls a function in the parent, first iframe and second iframe.
Hope this helps!
<!------- test.html -------->
<html>
<head>
<script type="text/javascript">
function parent_function() {
alert('parent');
}
function doit() {
parent_function();
document.getElementsByTagName('iframe')[0].contentWindow.iframe1_function();
document.getElementsByTagName('iframe')[0].contentWindow.document.getElementsByTagName('iframe')[0].contentWindow.iframe2_function();
}
</script>
</head>
<body>
main
do it
<iframe src='iframe1.html'>
</body>
</html>
<!------- iframe1.html -------->
<html>
<head>
<script type="text/javascript">
function iframe1_function() {
alert('iframe1');
}
</script>
</head>
<body>
frame1
<iframe src='iframe2.html'>
</body>
</html>
<!------- iframe2.html -------->
<html>
<head>
<script type="text/javascript">
function iframe2_function() {
alert('iframe2');
}
</script>
</head>
<body>
frame2
</body>
</html>
A fast way to select an iframe is to select it in the dom explorer, then in the js console, you can run $0.contentWindow.myFunction()

Categories