Pass value to iframe from a window - javascript

I need to send a value to an iframe.
The iframe is present within the current window. How can I achieve this?
I need to do it with javascript in the parent window that contains the iframe.

First, you need to understand that you have two documents: The frame and the container (which contains the frame).
The main obstacle with manipulating the frame from the container is that the frame loads asynchronously. You can't simply access it any time, you must know when it has finished loading. So you need a trick. The usual solution is to use window.parent in the frame to get "up" (into the document which contains the iframe tag).
Now you can call any method in the container document. This method can manipulate the frame (for example call some JavaScript in the frame with the parameters you need). To know when to call the method, you have two options:
Call it from body.onload of the frame.
Put a script element as the last thing into the HTML content of the frame where you call the method of the container (left as an exercise for the reader).
So the frame looks like this:
<script>
function init() { window.parent.setUpFrame(); return true; }
function yourMethod(arg) { ... }
</script>
<body onload="init();">...</body>
And the container like this:
<script>
function setUpFrame() {
var frame = window.frames['frame-id'].contentWindow;
frame.yourMethod('hello');
}
</script>
<body><iframe name="frame-id" src="..."></iframe></body>

Depends on your specific situation, but if the iframe can be deployed after the rest of the page's loading, you can simply use a query string, a la:
<iframe src="some_page.html?somedata=5&more=bacon"></iframe>
And then somewhere in some_page.html:
<script>
var params = location.href.split('?')[1].split('&');
data = {};
for (x in params)
{
data[params[x].split('=')[0]] = params[x].split('=')[1];
}
</script>

Here's another solution, usable if the frames are from different domains.
var frame = /*the iframe DOM object*/;
frame.contentWindow.postMessage({call:'sendValue', value: /*value*/}, /*frame domain url or '*'*/);
And in the frame itself:
window.addEventListener('message', function(event) {
var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
if (origin !== /*the container's domain url*/)
return;
if (typeof event.data == 'object' && event.data.call=='sendValue') {
// Do something with event.data.value;
}
}, false);
Don't know which browsers support this, though.

Use the frames collection.
From the link:
var frames = window.frames; // or // var frames = window.parent.frames;
for (var i = 0; i < frames.length; i++) {
// do something with each subframe as frames[i]
frames[i].document.body.style.background = "red";
}
If the iframe has a name you may also do the following:
window.frames['ponies'].number_of_ponies = 7;
You can only do this if the two pages are served from the same domain.

Two more options, which are not the most elegant but probably easier to understand and implement, especially in case the data that the iframe needs from its parent is just a few vars, not complex objects:
Using the URL Fragment Identifier (#)
In the container:
<iframe name="frame-id" src="http://url_to_iframe#dataToFrame"></iframe>
In the iFrame:
<script>
var dataFromDocument = location.hash.replace(/#/, "");
alert(dataFromDocument); //alerts "dataToFrame"
</script>
Use the iFrame's name
(I don't like this solution - it's abusing the name attribute, but it's an option so I'm mentioning it for the record)
In the container:
<iframe name="dataToFrame" src="http://url_to_iframe"></iframe>
In the iFrame:
<script type="text/javascript">
alert(window.name); // alerts "dataToFrame"
</script>

We can use "postMessage" concept for sending data to an underlying iframe from main window.
you can checkout more about postMessage using this link
add the below code inside main window page
// main window code
window.frames['myFrame'].contentWindow.postMessage("Hello World!");
we will pass "Hello World!" message to an iframe contentWindow with iframe id="myFrame".
now add the below code inside iframe source code
// iframe document code
function receive(event) {
console.log("Received Message : " + event.data);
}
window.addEventListener('message', receive);
in iframe webpage we will attach an event listener to receive event and in 'receive' callback we will print the data to console

Incase you're using angular and an iframe inside, you'll need need to listen to the iframe to finish loading. You can do something like this:
document.getElementsByTagName("iframe")[0].addEventListener('load', () => {
document.getElementsByTagName("iframe")[0].contentWindow.postMessage(
{
call: 'sendValue',
value: 'data'
},
window.location.origin)
})
You will have to get the iframe one way or another (there are better ways to do it in angular) and then wait for it to load. Or else the listener won't be attached to it even if you do it inside lifecycle methods like ngAfterViewInit()

Have a look at the link below, which suggests it is possible to alter the contents of an iFrame within your page with Javascript, although you are most likely to run into a few cross browser issues. If you can do this you can use the javascript in your page to add hidden dom elements to the iFrame containing your values, which the iFrame can read.
Accessing the document inside an iFrame

Just another way.
From iframe you can add event listeners and dispatch events into parent document:
parent.document.addEventListener('iframe-event', (e) => {
console.log('iframe-event', e.detail);
});
setTimeout(() => {
console.log('dispatchEvent from iframe');
const event = new CustomEvent('frame-ready', { detail: 'parent event dispatched from iframe' });
parent.document.dispatchEvent(event);
}, 1000);
And from parent you can add event listeners and dispatch events in its own document:
document.addEventListener('frame-ready', (e) => {
const event = new CustomEvent('iframe-event', { detail: 'iframe event dispatched from parent' });
document.dispatchEvent(event);
});
Also if in any case you need to open this frame in a new tab you can still use events for communication.
From your frame/tab:
if (opener) {
const event = new CustomEvent('frame-ready', { detail: 'parent event dispatched from new tab' });
opener.document.dispatchEvent(event);
}
From your parent/opener:
window.open('my-frame.html', '_blank');
document.addEventListener('frame-ready', (e) => {
const event = new CustomEvent('iframe-event', { detail: 'iframe event dispatched from parent' });
document.dispatchEvent(event);
});
Just be aware that window.open will expose your DOM to next page it opens, so if you use it to open any third part url, you must always use rel=noopener to avoid security issues:
window.open('third-part-url.html', '_blank', 'noopener');

In your main homepage, add this line-
window.postMessage("Hello data from Homepage");
Inside your iframe , add this line-
window.addEventListener("message", receiveDataFromWeb);
const receiveDataFromWeb= (data)=> {
console.log(data);
//this should print Hello data from Homepage
}

What you have to do is to append the values as parameters in the iframe src (URL).
E.g. <iframe src="some_page.php?somedata=5&more=bacon"></iframe>
And then in some_page.php file you use php $_GET['somedata'] to retrieve it from the iframe URL. NB: Iframes run as a separate browser window in your file.

Related

How can I run a script in another (newly-opened) tab?

I am trying to run a script in a new tab. The code I use is this:
$ = jQuery;
function openAndPush(url, id) {
var win = window.open('https://example.com' + url + '?view=map');
var element = $('<script type="text/javascript">console.log("Starting magic...");var region_id='+id+';$=jQuery;var p=$(\'div["se:map:paths"]\').attr(\'se:map:paths\');if(p){console.log("Found! pushing..."); $.get(\'https://localhost:9443/addPolygon\', {id: region_id, polygon: p}, function(){console.log("Done!")})}else{console.log("Not found!");}</script>').get(0);
setTimeout(function(){ win.document.body.appendChild(element);
console.log('New script appended!') }, 10000);
}
Considering the following:
I was inspired in this answer, but used jQuery instead.
I run this code in an inspector/console, from another page in https://example.com (yes, the actual domain is not example.com - but the target url is always in the same domain with respect to the original tab) to avoid CORS errors.
When I run the function (say, openAndPush('/target', 1)) and then inspect the code in another inspector, one for the new window, the console message Starting magic... is not shown (I wait the 10 seconds and perhaps more). However the new DOM element (this script I am creating) is shown in the Elements tab (and, in the first console/inspector, I can see the New script appended! message).
(In both cases jQuery is present, but not occupying the $ identifier, which seems to be undefined - so I manually occupy it)
What I conclude is that my script is not being executed in the new window.
What am I missing? How can I ensure the code is being executed?
Instead of embedding script element in the document, do this.
wrap the code that you want to run in another tab, into a function.
bind that wrapped function to the new tab's window
Call that function
Here's the code that I ran in my console and it worked for me i.e another tab was opened and alert was displayed.
function openAndPush(url, id) {
var win = window.open('https://www.google.com');
win.test = function () {
win.alert("Starting magic...");
}
win.test();
setTimeout(function () {
win.document.body.appendChild(element);
console.log('New script appended!')
}, 10000);
}
Found that my error consisted on the origin document being referenced when creating a new script node, instead of the target document (i.e. win.document). What I needed is to change the code to reference the new document and create the node directly, no jQuery in the middle at that point. So I changed my code like this:
function openAndPush(url, id) {
var win = window.open('https://streeteasy.com' + url + '?view=map');
var element = win.document.createElement('script');
element.type='text/javascript';
element.innerHTML = 'console.log("Starting magic...");var region_id='+id+';$=jQuery;var p=$(\'div[se\\\\:map\\\\:paths]\').attr(\'se:map:paths\');if(p){console.log("Found! pushing..."); $.get(\'https://localhost:9443/addPolygon\', {id: region_id, polygon: p}, function(){console.log("Done!")})}else{console.log("Not found! searched in: ", document);}'
setTimeout(function(){ win.document.body.appendChild(element); console.log('New script appended!') }, 10000);
}
With this code something is essentially happening: The JS code is being parsed (and its node created) in the context of the new document. Older alternatives involved the origin console (since the origin document was implicitly referenced).
It's bad practice to send scripts to another webpage. You can pass some query params using a complicated URL and handle it by a source code from another webpage, it's much better:
function doMagicAtUrlByRegionId (url, regionId) {
window.open(`https://example.com${url}?view=map&magic=true&region_id=${regionId}`);
}

Access parent frame from IFRAME using JavaScript [duplicate]

Well, I have an IFrame, which calls a same domain page.
My problem is that I want to access some information from this parent Iframe from this called page (from JavaScript). How can I access this Iframe?
Details: There are several Iframes just like this one, that can have the same page loaded, because I am programming a Windows environment. I intend to close this Iframe, that's why I need to know which I should close from inside him. I have an array keeping references to these Iframes.
EDIT: There iframes are generated dynamically
Also you can set name and ID to equal values
<iframe id="frame1" name="frame1" src="any.html"></iframe>
so you will be able to use next code inside child page
parent.document.getElementById(window.name);
Simply call window.frameElement from your framed page.
If the page is not in a frame then frameElement will be null.
The other way (getting the window element inside a frame is less trivial) but for sake of completeness:
/**
* #param f, iframe or frame element
* #return Window object inside the given frame
* #effect will append f to document.body if f not yet part of the DOM
* #see Window.frameElement
* #usage myFrame.document = getFramedWindow(myFrame).document;
*/
function getFramedWindow(f)
{
if(f.parentNode == null)
f = document.body.appendChild(f);
var w = (f.contentWindow || f.contentDocument);
if(w && w.nodeType && w.nodeType==9)
w = (w.defaultView || w.parentWindow);
return w;
}
I would recommend using the postMessage API.
In your iframe, call:
window.parent.postMessage({message: 'Hello world'}, 'http://localhost/');
In the page you're including the iframe you can listen for events like this:
window.addEventListener('message', function(event) {
if(event.origin === 'http://localhost/')
{
alert('Received message: ' + event.data.message);
}
else
{
alert('Origin not allowed!');
}
}, false);
By the way, it is also possible to do calls to other windows, and not only iframes.
Read more about the postMessage API on John Resigs blog here
Old question, but I just had this same issue and found a way to get the iframe. It's simply a matter of iterating through the parent window's frames[] array and testing each frame's contentWindow against the window in which your code is running. Example:
var arrFrames = parent.document.getElementsByTagName("IFRAME");
for (var i = 0; i < arrFrames.length; i++) {
if (arrFrames[i].contentWindow === window) alert("yay!");
}
Or, using jQuery:
parent.$("iframe").each(function(iel, el) {
if(el.contentWindow === window) alert("got it");
});
This method saves assigning an ID to each iframe, which is good in your case as they are dynamically created. I couldn't find a more direct way, since you can't get the iframe element using window.parent - it goes straight to the parent window element (skipping the iframe). So looping through them seems the only way, unless you want to use IDs.
you can use parent to access the parent page. So to access a function it would be:
var obj = parent.getElementById('foo');
Once id of iframe is set, you can access iframe from inner document as shown below.
var iframe = parent.document.getElementById(frameElement.id);
Works well in IE, Chrome and FF.
Maybe just use
window.parent
into your iframe to get the calling frame / windows. If you had multiple calling frame, you can use
window.top
Try this, in your parent frame set up you IFRAMEs like this:
<iframe id="frame1" src="inner.html#frame1"></iframe>
<iframe id="frame2" src="inner.html#frame2"></iframe>
<iframe id="frame3" src="inner.html#frame3"></iframe>
Note that the id of each frame is passed as an anchor in the src.
then in your inner html you can access the id of the frame it is loaded in via location.hash:
<button onclick="alert('I am frame: ' + location.hash.substr(1))">Who Am I?</button>
then you can access parent.document.getElementById() to access the iframe tag from inside the iframe
// just in case some one is searching for a solution
function get_parent_frame_dom_element(win)
{
win = (win || window);
var parentJQuery = window.parent.jQuery;
var ifrms = parentJQuery("iframe.upload_iframe");
for (var i = 0; i < ifrms.length; i++)
{
if (ifrms[i].contentDocument === win.document)
return ifrms[i];
}
return null;
}

Holy grail for determining whether or not local iframe has loaded

Firstly, I see this question asked a few times but no answers seem satisfactory. What I am looking for is to be able to call a script at anytime and determine whether or not an iframe has loaded - and to not limit the script to require being added to the iframe tag itself in an onload property.
Here's some background: I have been working on an unobtrusive script to try and determine whether or not local iframes in the dom have loaded, this is because one of our clients includes forms on their website in iframes and many of them open in lightboxes - which dynamically add the iframes into the dom at any time. I can attach to the open event of the lightbox, but its hit or miss as to whether I can "catch" the iframe before it has loaded.
Let me explain a little more.
In my testing I've determined that the onload event will only fire once - and only if it is bound before the iframe actually loads. For example: This page should only alert "added to iframe tag" and the listener that is attached afterward does not fire - to me that makes sense. (I'm using the iframe onload property for simple example).
https://jsfiddle.net/g1bkd3u1/2/
<script>
function loaded () {
alert ("added to iframe tag");
$("#test").load(function(){
alert("added after load finished");
});
};
</script>
<iframe onload="loaded()" id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
My next approach was to check the document ready state of the iframe which seems to work in almost all of my testing except chrome which reports "complete" - I was expecting "Access Denied" for cross domain request. I'm ok with a cross domain error because I can disregard the iframe since I am only interested in local iframes - firefox reports "unintialized" which I'm ok with because I know I can then attach an onload event.
Please open in Chrome:
https://jsfiddle.net/g1bkd3u1/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
alert($("#test").contents()[0].readyState);
</script>
I've found that if I wait just 100ms - then the iframe seems to report as expected (a cross domain security exception - which is what I want - but I don't want to have to wait an arbitrary length).
https://jsfiddle.net/g1bkd3u1/4/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
setTimeout(function () {
try {
alert($("#test").contents()[0].readyState);
} catch (ignore) {
alert("cross domain request");
}
}, 100);
</script>
My current workaround / solution is to add the onload event handler, then detach the iframe from the dom, then insert it back into the dom in the same place - now the onload event will trigger. Here's an example that waits 3 seconds (hoping thats enough time for the iframe to load) to show that detaching and re-attaching causes the iframe onload event to fire.
https://jsfiddle.net/g1bkd3u1/5/
<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
setTimeout(function(){
var placeholder = $("<span>");
$("#test").load(function(){
alert("I know the frame has loaded now");
}).after(placeholder).detach().insertAfter(placeholder);
placeholder.detach();
}, 3000);
</script>
While this works it leaves me wondering if there are better more elegant techniques for checking iframe load (unobtrusively)?
Thank you for your time.
Today I actually ran into a bug where my removing and re-inserting of iframes was breaking a wysiwyg editor on a website. So I created the start of a small jQuery plugin to check for iframe readiness. It is not production ready and I have not tested it much, but it should provide a nicer alternative to detaching and re-attaching an iframe - it does use polling if it needs to, but should remove the setInterval when the iframe is ready.
It can be used like:
$("iframe").iready(function() { ... });
https://jsfiddle.net/q0smjkh5/10/
<script>
(function($, document, undefined) {
$.fn["iready"] = function(callback) {
var ifr = this.filter("iframe"),
arg = arguments,
src = this,
clc = null, // collection
lng = 50, // length of time to wait between intervals
ivl = -1, // interval id
chk = function(ifr) {
try {
var cnt = ifr.contents(),
doc = cnt[0],
src = ifr.attr("src"),
url = doc.URL;
switch (doc.readyState) {
case "complete":
if (!src || src === "about:blank") {
// we don't care about empty iframes
ifr.data("ready", "true");
} else if (!url || url === "about:blank") {
// empty document still needs loaded
ifr.data("ready", undefined);
} else {
// not an empty iframe and not an empty src
// should be loaded
ifr.data("ready", true);
}
break;
case "interactive":
ifr.data("ready", "true");
break;
case "loading":
default:
// still loading
break;
}
} catch (ignore) {
// as far as we're concerned the iframe is ready
// since we won't be able to access it cross domain
ifr.data("ready", "true");
}
return ifr.data("ready") === "true";
};
if (ifr.length) {
ifr.each(function() {
if (!$(this).data("ready")) {
// add to collection
clc = (clc) ? clc.add($(this)) : $(this);
}
});
if (clc) {
ivl = setInterval(function() {
var rd = true;
clc.each(function() {
if (!$(this).data("ready")) {
if (!chk($(this))) {
rd = false;
}
}
});
if (rd) {
clearInterval(ivl);
clc = null;
callback.apply(src, arg);
}
}, lng);
} else {
clc = null;
callback.apply(src, arg);
}
} else {
clc = null;
callback.apply(this, arguments);
}
return this;
};
}(jQuery, document));
</script>
The example waits until the window has loaded to dynamically add an iframe to the DOM, it then alerts its document's readyState - which in chrome displays "complete", incorrectly. The iready function should be called after and an attempt to output the document's readyState proves cross domain exception - again this has not been thoroughly tested but works for what I need.
I encountered a similar issue in that I had an iframe and needed to modify its' document once it had finished loading.
IF you know or can control the content of the loaded document in the iFrame, then you could simply check for/add an element that you could check the existence of in order to then update the iframe document.
At least then you know the elements you want to work with are loaded in to the document.
In my case, I called a function, which itself checked for the existence of my known element that would always be found after the elements I needed to update had already been loaded - in the case it was not found, it called itself again through setTimeout().
function updateIframeContents() {
if ($("#theIframe").contents().find('.SaveButton').length > 0) {
// iframe DOM Manipulation
} else {
setTimeout(updateIframeContents, 250);
}
}
updateIframeContents();

Reading Iframe Content in Iframe Load

I just wanna learn how to read Iframe content in onLoad event of iframe and write it's content to the main page ? Thanks..
You can use this jquery function in parent page and it also supports many other function to add and remove stuffs:
<script type="text/javascript">
function myFunction() {
var $currIFrame = $('#Frame1');
$currIFrame.contents().find("body #idofElement").val('Value i want to set');
}
</script>
In above code: #idofElement is the element from HTML page in iframe whose value you want to set. I Hope it helps You..
I have struggled with same this past day. It seems to matter how you access the iframe. If you use document.getElementById() you get an Iframe object, which has no onload event. However, if you access through window.frames[] array, for example
var iframeWindow = top.frames['iframeID'],
you get a window object, which does have onload event.
(ie uses the frame id attribute , but ff uses name attribute. So use both and make the same)
You can then assign
iframeWindow.onload=function(){iframeContent=iframeWindow.document.body.innerHTML;};
Notice, since iframeWindow is a window object, you use window syntax to access content.
jQuery("#xiframe").load(function()
{
var doc = null;
try{
doc = this.document || this.contentDocument || this.contentWindow && xiframe.contentWindow.document || null;
} catch(err) {
alert('error: ' + err.description);
}
try {
if(!doc) {
alert('error');
return false;
}
} catch(err) {
alert('error: ' + err.description);
return false;
}
alert(String(jQuery(doc.body).html());
}
document.getElementById('iframeID').contentWindow.onload = function(){
top.document.innerHTML = this.document.innerHTML;
}
parent document (the page on which the iframe is displayed)
child document (the page displayed inside the iframe)
If these two documents are in the same domain, you can use the window.parent.document object in the child document's onload event handler to access the parent document.

How to identify if a webpage is being loaded inside an iframe or directly into the browser window?

I am writing an iframe based facebook app. Now I want to use the same html page to render the normal website as well as the canvas page within facebook. I want to know if I can determine whether the page has been loaded inside the iframe or directly in the browser?
Browsers can block access to window.top due to same origin policy. IE bugs also take place. Here's the working code:
function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
top and self are both window objects (along with parent), so you're seeing if your window is the top window.
When in an iframe on the same origin as the parent, the window.frameElement method returns the element (e.g. iframe or object) in which the window is embedded. Otherwise, if browsing in a top-level context, or if the parent and the child frame have different origins, it will evaluate to null.
window.frameElement
? 'embedded in iframe or object'
: 'not embedded or cross-origin'
This is an HTML Standard with basic support in all modern browsers.
if ( window !== window.parent )
{
// The page is in an iframe
}
else
{
// The page is not in an iframe
}
I'm not sure how this example works for older Web browsers but I use this for IE, Firefox and Chrome without an issue:
var iFrameDetection = (window === window.parent) ? false : true;
RoBorg is correct, but I wanted to add a side note.
In IE7/IE8 when Microsoft added Tabs to their browser they broke one thing that will cause havoc with your JS if you are not careful.
Imagine this page layout:
MainPage.html
IframedPage1.html (named "foo")
IframedPage2.html (named "bar")
IframedPage3.html (named "baz")
Now in frame "baz" you click a link (no target, loads in the "baz" frame) it works fine.
If the page that gets loaded, lets call it special.html, uses JS to check if "it" has a parent frame named "bar" it will return true (expected).
Now lets say that the special.html page when it loads, checks the parent frame (for existence and its name, and if it is "bar" it reloads itself in the bar frame. e.g.
if(window.parent && window.parent.name == 'bar'){
window.parent.location = self.location;
}
So far so good. Now comes the bug.
Lets say instead of clicking on the original link like normal, and loading the special.html page in the "baz" frame, you middle-clicked it or chose to open it in a new Tab.
When that new tab loads (with no parent frames at all!) IE will enter an endless loop of page loading! because IE "copies over" the frame structure in JavaScript such that the new tab DOES have a parent, and that parent HAS the name "bar".
The good news, is that checking:
if(self == top){
//this returns true!
}
in that new tab does return true, and thus you can test for this odd condition.
The accepted answer didn't work for me inside the content script of a Firefox 6.0 Extension (Addon-SDK 1.0): Firefox executes the content script in each: the top-level window and in all iframes.
Inside the content script I get the following results:
(window !== window.top) : false
(window.self !== window.top) : true
The strange thing about this output is that it's always the same regardless whether the code is run inside an iframe or the top-level window.
On the other hand Google Chrome seems to execute my content script only once within the top-level window, so the above wouldn't work at all.
What finally worked for me in a content script in both browsers is this:
console.log(window.frames.length + ':' + parent.frames.length);
Without iframes this prints 0:0, in a top-level window containing one frame it prints 1:1, and in the only iframe of a document it prints 0:1.
This allows my extension to determine in both browsers if there are any iframes present, and additionally in Firefox if it is run inside one of the iframes.
I'm using this:
var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
Use this javascript function as an example on how to accomplish this.
function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe
// and the domains are different.
var myresult = true;
try {
var tophref = top.location.href;
var tophostname = top.location.hostname.toString();
var myhref = location.href;
if (tophref === myhref) {
myresult = true;
} else if (tophostname !== "www.yourdomain.com") {
myresult = false;
}
} catch (error) {
// error is a permission error that top.location.href is not accessible
// (which means parent domain <> iframe domain)!
myresult = false;
}
return myresult;
}
Best-for-now Legacy Browser Frame Breaking Script
The other solutions did not worked for me. This one works on all browsers:
One way to defend against clickjacking is to include a "frame-breaker" script in each page that should not be framed. The following methodology will prevent a webpage from being framed even in legacy browsers, that do not support the X-Frame-Options-Header.
In the document HEAD element, add the following:
<style id="antiClickjack">body{display:none !important;}</style>
First apply an ID to the style element itself:
<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
This way, everything can be in the document HEAD and you only need one method/taglib in your API.
Reference: https://www.codemagi.com/blog/post/194
I actually used to check window.parent and it worked for me, but lately window is a cyclic object and always has a parent key, iframe or no iframe.
As the comments suggest hard comparing with window.parent works. Not sure if this will work if iframe is exactly the same webpage as parent.
window === window.parent;
Since you are asking in the context of a facebook app, you might want to consider detecting this at the server when the initial request is made. Facebook will pass along a bunch of querystring data including the fb_sig_user key if it is called from an iframe.
Since you probably need to check and use this data anyway in your app, use it to determine the the appropriate context to render.
function amiLoadedInIFrame() {
try {
// Introduce a new propery in window.top
window.top.dummyAttribute = true;
// If window.dummyAttribute is there.. then window and window.top are same intances
return !window.dummyAttribute;
} catch(e) {
// Exception will be raised when the top is in different domain
return true;
}
}
Following on what #magnoz was saying, here is a code implementation of his answer.
constructor() {
let windowLen = window.frames.length;
let parentLen = parent.frames.length;
if (windowLen == 0 && parentLen >= 1) {
this.isInIframe = true
console.log('Is in Iframe!')
} else {
console.log('Is in main window!')
}
}
It's an ancient piece of code that I've used a few times:
if (parent.location.href == self.location.href) {
window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
If you want to know if the user is accessing your app from facebook page tab or canvas check for the Signed Request. If you don't get it, probably the user is not accessing from facebook.
To make sure confirm the signed_request fields structure and fields content.
With the php-sdk you can get the Signed Request like this:
$signed_request = $facebook->getSignedRequest();
You can read more about Signed Request here:
https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/
and here:
https://developers.facebook.com/docs/reference/login/signed-request/
This ended being the simplest solution for me.
<p id="demofsdfsdfs"></p>
<script>
if(window.self !== window.top) {
//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";
}else{
//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}
</script>
if (window.frames.length != parent.frames.length) { page loaded in iframe }
But only if number of iframes differs in your page and page who are loading you in iframe. Make no iframe in your page to have 100% guarantee of result of this code
Write this javascript in each page
if (self == top)
{ window.location = "Home.aspx"; }
Then it will automatically redirects to home page.

Categories