iframe - location - same origin policy - javascript

As I was always believing, iframe properties (if the iframe is loaded from another origin) can not be get but set.
I tried some little testcases, but it seems that I can always get the properties.
Am I doing something wrong in setting up the example?
<iframe src="http://www.wikipedia.org" id="iframe"></iframe>
<script>
try {
alert(document.getElementById("iframe").src);
} catch(e) {
alert(e);
}
</script>
The above example alerts the correct location in my tests.
Regards

You are not accessing some content elements/properties of a contained document. You are just getting the src attribute of the iframe that is set by the outer document. Just try this:
iframeElement.contentDocument.body.style.backgroundColor = "red";

Related

Get element in an HTML document within another HTML document [duplicate]

I have this HTML code:
<html>
<head>
<script type="text/javascript">
function GetDoc(x)
{
return x.document ||
x.contentDocument ||
x.contentWindow.document;
}
function DoStuff()
{
var fr = document.all["myframe"];
while(fr.ariaBusy) { }
var doc = GetDoc(fr);
if (doc == document)
alert("Bad");
else
alert("Good");
}
</script>
</head>
<body>
<iframe id="myframe" src="http://example.com" width="100%" height="100%" onload="DoStuff()"></iframe>
</body>
</html>
The problem is that I get message "Bad". That mean that the document of iframe is not got correctly, and what is actualy returned by GetDoc function is the parent document.
I would be thankful, if you told where I do my mistake. (I want to get document hosted in IFrame.)
Thank you.
You should be able to access the document in the IFRAME using the following code:
document.getElementById('myframe').contentWindow.document
However, you will not be able to do this if the page in the frame is loaded from a different domain (such as google.com). This is because of the browser's Same Origin Policy.
The problem is that in IE (which is what I presume you're testing in), the <iframe> element has a document property that refers to the document containing the iframe, and this is getting used before the contentDocument or contentWindow.document properties. What you need is:
function GetDoc(x) {
return x.contentDocument || x.contentWindow.document;
}
Also, document.all is not available in all browsers and is non-standard. Use document.getElementById() instead.
In case you get a cross-domain error:
If you have control over the content of the iframe - that is, if it is merely loaded in a cross-origin setup such as on Amazon Mechanical Turk - you can circumvent this problem with the <body onload='my_func(my_arg)'> attribute for the inner html.
For example, for the inner html, use the this html parameter (yes - this is defined and it refers to the parent window of the inner body element):
<body onload='changeForm(this)'>
In the inner html :
function changeForm(window) {
console.log('inner window loaded: do whatever you want with the inner html');
window.document.getElementById('mturk_form').style.display = 'none';
</script>
You can also use:
document.querySelector('iframe').contentDocument

Open <div> popup outside iFrame

Info: I was working on it for so long, I have a webpage that contains an iframe. Inside that iframe i have opened a page (application) from my own site.
Question: I'm trying to get the <div class = "ps-lightbox"> </ div> inside that iframe out of the iframe. but i cant figure it out with jQuery..
I know it sounds confusing. But I hope you understand my explanation.
Does anyone know how to fix this? You could save my day..
Screenshot of the webpage <
You can not access the elements which are not part of iframe document. But if you have iframe of your own website then window.postMessage can do the trick.
Consider below example:
mainPage.html
<html>
<head>
<script type="text/javascript">
window.addEventListener("message", function(evnet){
if(event.type === "GET_SOME_ELEMENT"){
var iframeWindow = document.getElementsById("iframe1")[0].contentWindow;
iframeWindow.postMessage("POST_SOME_ELEMENT", "TARGET_ORIGIN", {element: $(".some-element")}
}
});
<script/>
</head>
<body>
<div class="some-element"/>
<iframe id="iframe1" src="iframePage.html"/>
</body>
</html>
iframePage.html
<html>
<head>
<script type="text/javascript">
if(window.parent){
window.parent.postMessage("GET_SOME_ELEMENT", "TARGET_ORIGIN");
window.addEventListener("message", function(evnet){
if(event.type === "POST_SOME_ELEMENT"){
console.log(event.data.element);
}
});
}
<script/>
</head>
</html>
The exact question is how to do it with pure JavaScript, not with jQuery.
But I always use the solution that can be found in jQuery's source code. It's just one line of native JavaScript.
For me, it's the best, easily readable and even afaik the shortest way to get the content of the iframe.
First get your iframe
var iframe = document.getElementById('id_description_iframe');
// or
var iframe = document.querySelector('#id_description_iframe');
And then use jQuery's solution
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
It works even in the Internet Explorer which does this trick during
the contentWindow property of the iframe object. Most other browsers
use the contentDocument property and that is the reason why we proof
this property first in this OR condition. If it is not set to try
contentWindow.document.
Select elements in iframe
Then you can usually use getElementById() or even querySelectorAll() to select the DOM-Element from the iframeDocument:
if (!iframeDocument) {
throw "iframe couldn't be found in DOM.";
}
var iframeContent = iframeDocument.getElementById('frameBody');
// or
var iframeContent = iframeDocument.querySelectorAll('#frameBody');
Call functions in the iframe
Get just the window element from iframe to call some global functions, variables or whole libraries (e.g. jQuery):
var iframeWindow = iframe.contentWindow;
// you can even call jQuery or other frameworks
// if it is loaded inside the iframe
iframeContent = iframeWindow.jQuery('#frameBody');
// or
iframeContent = iframeWindow.$('#frameBody');
// or even use any other global variable
iframeWindow.myVar = window.myVar;
// or call a global function
var myVar = iframeWindow.myFunction(param1 /*, ... */);
Note
All this is possible if you observe the same-origin policy.
This might help you
var html = $(".ps-lightbox").contents().find("body").html()
And btw, you can get access to iframe's content only from the same origin due to XSS protection
Make sure your code is inside jQuery ready event.
// This won't work
$("#iframe").contents().find('.ps-lightbox');
// This will work
$(function() {
$("#iframe").contents().find('.ps-lightbox');
})

Get all elements inside iframe tag

this is my part of code now i'm using iframe tag and loaded epub on iframe tag
then i don't know how to get all elements inside iframe tag.
jQuery(document).ready(function($) {
var tmp = $('#epub_loader iframe').contents().find('body').html();
alert(tmp);
});
<iframe id="epub_loader" href="test.epub" ></iframe>
`
Assuming both your frames are on the same domain and there is no restriction with Same Domain Policy, you can use the following code from the "parent" frame to get an element in the "child" iframe (in your case body tag).
Pseudo code, you need to actually point to your iframe DOM by id:
var html = document.getElementById('iframe').contentDocument.body.innerHTML;
Notes: In case iframe is on a different domain, you have limited access for browser security reasons.
The thing you need is to wait document will be fully loaded coz you are used iframe,then you should call ....
jQuery(document).ready(function() {
window.onload = function () { //call when iframe is fully loaded
var tmp = $('#epub_loader').contents().find('body').html();
alert(tmp);
};
});

Get the iframe name from the source document

I have following iframe in a parent page:
<html>
....
<iframe src="child.html" name="variedName" id="variedId"></iframe>
...
</html>
Is there any way that make Javascript from child.html to get the name value or the id of the iframe that included it?
I need this because I want to add some markup around the iframe that is going to include child.html in the parent page using window.parent
Well, the quick and dirty solution would be to give the iframe the same name and id and access the iframe within the child page like this:
parent.document.getElementById(window.name);
Yes, but only if the pages share the same origin.
You can do something like:
var parent_window = window.parent;
iframes = parent_window.document.getElementsByTag("iframe");
if (iframes[0].window === window) {
// found it
}
The if statement might need some tweaking but I think this works.
Besides the presented solutions, You can use this:
parent.document.getElementsByName(window.name)[0];
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByName
Or this:
parent.document.querySelector('iframe[src="'+location+'"]');
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/document.querySelector
Or this "frankencode":
(function(){
for(var i=0,frames=parent.frames,l=frames.length;i<l;i++)
{
if(frames[i].window===window)
{
return frames[i].window;
}
}
})();
If you have jQuery:
$('iframe[name="'+window.name+'"]',parent); //method 1
$('iframe[src="'+location+'"]',parent); //method 2
$('iframe',parent).filter(function(){ //a different method
return this.window===window;
}).eq(0);
And many more ways...

Calling a parent window function from an iframe

I want to call a parent window JavaScript function from an iframe.
<script>
function abc()
{
alert("sss");
}
</script>
<iframe id="myFrame">
<a onclick="abc();" href="#">Call Me</a>
</iframe>
<a onclick="parent.abc();" href="#" >Call Me </a>
See window.parent
Returns a reference to the parent of the current window or subframe.
If a window does not have a parent, its parent property is a reference to itself.
When a window is loaded in an <iframe>, <object>, or <frame>, its parent is the window with the element embedding the window.
Window.postMessage()
This method safely enables cross-origin communication.
And if you have access to parent page code then any parent method can be called as well as any data can be passed directly from Iframe. Here is a small example:
Parent page:
if (window.addEventListener) {
window.addEventListener("message", onMessage, false);
}
else if (window.attachEvent) {
window.attachEvent("onmessage", onMessage, false);
}
function onMessage(event) {
// Check sender origin to be trusted
if (event.origin !== "http://example.com") return;
var data = event.data;
if (typeof(window[data.func]) == "function") {
window[data.func].call(null, data.message);
}
}
// Function to be called from iframe
function parentFunc(message) {
alert(message);
}
Iframe code:
window.parent.postMessage({
'func': 'parentFunc',
'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *
UPDATES:
Security note:
Always provide a specific targetOrigin, NOT *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site (comment by ZalemCitizen).
References:
Cross-document messaging
Window.postMessage()
Can I Use
I recently had to find out why this didn't work too.
The javascript you want to call from the child iframe needs to be in the head of the parent. If it is in the body, the script is not available in the global scope.
<head>
<script>
function abc() {
alert("sss");
}
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="parent.abc();" href="#">Click Me</a>
</iframe>
</body>
Hope this helps anyone that stumbles upon this issue again.
You can use
window.top
see the following.
<head>
<script>
function abc() {
alert("sss");
}
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="window.top.abc();" href="#">Click Me</a>
</iframe>
</body>
I have posted this as a separate answer as it is unrelated to my existing answer.
This issue recently cropped up again for accessing a parent from an iframe referencing a subdomain and the existing fixes did not work.
This time the answer was to modify the document.domain of the parent page and the iframe to be the same. This will fool the same origin policy checks into thinking they co-exist on exactly the same domain (subdomains are considered a different host and fail the same origin policy check).
Insert the following to the <head> of the page in the iframe to match the parent domain (adjust for your doctype).
<script>
document.domain = "mydomain.com";
</script>
Please note that this will throw an error on localhost development, so use a check like the following to avoid the error:
if (!window.location.href.match(/localhost/gi)) {
document.domain = "mydomain.com";
}
parent.abc() will only work on same domain due to security purposes. i tried this workaround and mine worked perfectly.
<head>
<script>
function abc() {
alert("sss");
}
// window of the iframe
var innerWindow = document.getElementById('myFrame').contentWindow;
innerWindow.abc= abc;
</script>
</head>
<body>
<iframe id="myFrame">
<a onclick="abc();" href="#">Click Me</a>
</iframe>
</body>
Hope this helps. :)
Another addition for those who need it. Ash Clarke's solution does not work if they are using different protocols so be sure that if you are using SSL, your iframe is using SSL as well or it will break the function. His solution did work for the domains itself though, so thanks for that.
The solution given by Ash Clarke for subdomains works great, but please note that you need to include the document.domain = "mydomain.com"; in both the head of the iframe page and the head of the parent page, as stated in the link same origin policy checks
An important extension to the same origin policy implemented for JavaScript DOM access (but not for most of the other flavors of same-origin checks) is that two sites sharing a common top-level domain may opt to communicate despite failing the "same host" check by mutually setting their respective document.domain DOM property to the same qualified, right-hand fragment of their current host name.
For example, if http://en.example.com/ and http://fr.example.com/ both set document.domain to "example.com", they would be from that point on considered same-origin for the purpose of DOM manipulation.
With Firefox and Chrome you can use :
<a href="whatever" target="_parent" onclick="myfunction()">
If myfunction is present both in iframe and in parent, the parent one will be called.
While some of these solutions may work, none of them follow best practices. Many assign global variables and you may find yourself making calls to multiple parent variables or functions, leading to a cluttered, vulnerable namespace.
To avoid this, use a module pattern. In the parent window:
var myThing = {
var i = 0;
myFunction : function () {
// do something
}
};
var newThing = Object.create(myThing);
Then, in the iframe:
function myIframeFunction () {
parent.myThing.myFunction();
alert(parent.myThing.i);
};
This is similar to patterns described in the Inheritance chapter of Crockford's seminal text, "Javascript: The Good Parts." You can also learn more at w3's page for Javascript's best practices. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals
A plugin helper gist that allows the parent window to call the child iframe windows functions and vice-versa, but all calls are asynchronous.
https://gist.github.com/clinuxrulz/77f341832c6025bf10f0b183ee85e072
This will also work cross-origin, but can only call functions that you export to the iframe from the parent and the parent window can only call funtions the iframe exports.

Categories