Execute Function when iFrame url Changes - javascript

I have a signup form which is inside an iframe on my site and I want to create a redirect when the url of the iframe changes (when user successfully signed-up).
These 2 sites are cross domain and I know that it is almost impossible to pull the url cross domains but is there a workaround? I know the src will not change and I was thinking to use onload(), when the iframe loads a second time (when user successfully signed-up), execute a function to redirect to a thank you page.

Here is an example using the javascript 'Porthole'.
Its possible, but keep in mind the safety issues with iframes. The solution: if you have control of the original page + iframe, you can 'trick' the browser by implementing some javascripts on both sides.
First create a 'proxy' page on both domains. Name it 'proxy.html' or something (note: you have to use 'porthole.min.js', you can get this from the sources in the bottom)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- Replace the url with your own location -->
<script type="text/javascript" src="porthole.min.js"></script>
<script type="text/javascript">
window.onload=function(){ Porthole.WindowProxyDispatcher.start(); };
</script>
</head>
<body>
</body>
</html>
On the parent page: (refer to the iframe proxy.html page)
<script type="text/javascript" src="porthole.min.js"></script>
<iframe id="guestFrame" name="guestFrame" src="http://iframe.otherdomain.com/"></iframe>
<script type="text/javascript">
var iframeDomain = 'http://iframe.otherdomain.com';
var redirectUrl = 'http://www.mydomain.com/redirect-to/signed-up';
function onMessage(messageEvent) {
if (messageEvent.origin == iframeDomain) {
if (messageEvent.data["action"]
&& messageEvent.data["action"] == 'signed-up) {
window.location.href = redirectUrl; // The final action!
// This is the eventual redirect that will happen
// once your visitor has signed-up within the iframe
}
}
}
var windowProxy;
window.onload=function(){
// Create a proxy window to send to and receive messages from the iFrame
windowProxy = new Porthole.WindowProxy(
'http://iframe.otherdomain.com/proxy.html', 'guestFrame');
// Register an event handler to receive messages;
windowProxy.addEventListener(onMessage);
};
</script>
On the iframe page (refer to the parent proxy.html page)
<script type="text/javascript">
var windowProxy;
window.onload=function(){
// Create a proxy window to send to and receive messages from the parent
windowProxy = new Porthole.WindowProxy(
'http://www.mydomain.com/proxy.html');
// Register an event handler to receive messages;
windowProxy.addEventListener(function(event) {
// handle event (not used here, the iframe does not need to listen)
});
};
</script>
From the iframe you can send a message with javascript to the parent page (and also the other way). If you use only 1 javascript within the iframe domain, you can do something like this to send a message to the parent frame when the url is changed to something specific, for example 'signed-up.php' (untested, but you'll get the idea)
<script type="text/javascript">
window.onload=function(){
if(window.location.href.indexOf("signed-up.php") > -1) {
windowProxy.post({'action': 'signed-up'}); // Send message to the parent frame
// On the parent page, the function 'onMessage' is triggered.
}
};
</script>
Sources:
http://ternarylabs.github.io/porthole/
Github: https://github.com/ternarylabs/porthole
Demo: http://sandbox.ternarylabs.com/porthole/

Related

Loading widget on web page

I'm trying to make a loadable widget that would call an api when a button is clicked.
Widget page itself
widget.html
<html>
<head>
<title>Widget</title>
</head>
<body>
<button id="test"></button>
<script>
window.onload = init;
function clicked() {
// some logic
}
function init() {
document.getElementById('test').addEventListener('click', clicked, false);
}
export {clicked}
</script>
</body>
</html>
The page it embeds on
index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Getting started</title>
</head>
<body>
<div>
<div id="widget_box"></div>
<script src="http://localhost:8080/js/widget.js" type="text/javascript"></script>
<script type="text/javascript">wdgt.init('widget_box');</script>
</div>
</body>
</html>
js code that loads the widget
widget.js
var wdgt= {
idBox: 'wdgt',
url_widget: 'http://localhost:8080/pages/widgets/widget.html',
url_style: 'http://localhost:8080/css/widget.css',
init: function (id) {
console.log("Begin Widget initialization");
if (!id) {
id = this.idBox;
}
if (document.getElementById(id)) {
this.addStyle();
try {
var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest;
var xhr = new XHR();
xhr.open('GET', this.url_widget, true);
xhr.onload = function () {
if (this.response) {
document.getElementById(id).innerHTML = this.response;
}
}
xhr.onerror = function () {
console.log('onerror ' + this.status);
}
xhr.send();
} catch (ignore) {
}
} else {
console.log('The specified block id="' + id + '" is missing');
}
},
addStyle: function () {
style = document.createElement('link');
style.rel = 'stylesheet';
style.type = 'text/css';
style.href = this.url_style;
document.head.appendChild(style);
}
}
If I open the widget in a separate window, the code attached to the button works. But when I try to embed it, nothing happens.
Moreover, in this script, document.getElementById() returns null when trying to find the button.
The back is a simple Spring application that returns index.html
TL;DR: It's not supposed to work. You should use iframe element to fetch and render external pages.
Your script widget.js is trying to render the contents of fetched widget.html into a <div> element.
The browser will to do the best, though it won't be able to create another DOM tree inside of <div>. Because when you feed a whole HTML page to innerHTML, you basically ask the browser to render a document inside a document. This is not allowed.
Still it will render the contents of you document's body. So you'll be able to see the button. But it won't execute any <script> tags. It's a safety measure to prevent XSS attacks. A couple of dirty ways to execute your code do exist, but I won't recommend them.
So what should you do to add an external widget into a page? The answer is neat: meet the <iframe>! This dude is created just for those things. For you case, you should rewrite index.html this way:
<!DOCTYPE HTML>
<html>
<head>
<title>Getting started</title>
</head>
<body>
<iframe src="http://localhost:8080/pages/widgets/widget.html" width="800" height="600"></iframe>
</body>
</html>
With iframes, you don't need to manually fetch your widget HTML. The browser will download and render it inside your iframe. Like a document inside a document with all the styles, embedded resources and scripts.
Please note, that when you embed something using iframe, security limitations apply. You won't be able to directly interact with your main page from inside the iframe and vice versa. It will be like a separate window inside you document. And it will have additional constraints. Please address to the docs.

JavaScript Message event not being fired [duplicate]

This question already has answers here:
How do you use window.postMessage across domains?
(3 answers)
Closed 5 years ago.
I have a simple HTML5 page with an iframe whose src attribute is initially empty string. The page renders without any JavaScript errors.
The src attribute of iframe element is only set when the window has loaded, so initially an empty iframe loads. The iframe src is being set to a page from another domain.
The problem I am facing is that the postMessage method works without throwing any errors, however the source page is not firing the message event even though it's set up before the iframe page starts loading. I am having the alert messages from iframe page show up, which means the postMessage method did not throw any errors.
Question
What am I missing when subscribing to the message event in source page?
Source page
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Cross domain iframe messaging</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script type="text/javascript">
var iframec = null;
window.addEventListener("load", function () {
iframec = document.getElementById("iframec");
//set up event listener for iframe object so it can receive message from page shown in iframe
iframec.contentWindow.addEventListener("message", function (event) {
alert("received: " + event.data);
}, false);
//load the iframe page but after you have set up to receive messages
iframec.src = "http://www.abcx.com";
});
</script>
</head>
<body>
<form id="form1">
<div>
<h1>Testing iframe messaging in a Cross Domain scenario</h1>
<p> Trying to send a message to an iframe that comes from a page in another domain. The postMessage method does not throw an error when called from the other domain page, but it's not being received by the page having iframe element in it.</p>
<div id="divComments"></div>
<iframe src="" id="iframec" name="iframec" style="border:none;margin:0;padding:0;width:100%; "></iframe>
</div>
</form>
</body>
</html>
Iframe Page JavaScript that is not throwing any error (i.e. page at http://www.abcx.com)
<script>
$( document ).ready(function() {
alert("loaded the iframe page on another domain. Just before postMessage");
window.postMessage("Some message was sent from other domain message", "*");
alert("loaded the iframe page on another domain. Just after postMessage");
});
</script>
You're hooking up the listener on the wrong window, and using the wrong window to send the message. (This is fairly easy to get wrong. :-) )
In the main window, you want to receive message events on the main window, not the iframe, so:
window.addEventListener("message", function (event) {
// ^^^^^^^
alert("received: " + event.data);
}, false);
In the iframe, you want to send to window.parent (well, parent), not window:
parent.postMessage("Some message was sent from other domain message", "*");
// ^^^^^^
With both of those changes, the message sent by the iframe is received by the main window.
I found a similar question here
On the page you're trying to load, it should be using top.postMessage or parent.postMessage
Additionally, you should be attaching the listener to the window, not the iframe (and make sure to filter the origin, or else localhost will throw you a false positive)
This is the version of yours I was playing with:
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script>
var iframec = null;
window.addEventListener("load", function () {
if(!iframec){
iframec = document.getElementById("iframec");
//set up event listener for iframe object so it can receive message from page shown in iframe
window.addEventListener("message", function (event) {
if(event.origin == '[your domain here]') alert("received from " + event.origin + ": " + event.data);
}, false);
//load the iframe page but after you have set up to receive messages
iframec.src = "[iframe target url]";
}
});
</script>
And the target for the iframe:
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script>
$( document ).ready(function() {
alert('loaded the page. Just before postMessage');
top.postMessage("Some message was sent from appsprocure", "*");
alert("loaded the page. Just after postMessage");
});
</script>
</head>
<body><h1>Hello!</h1></body>
</html>

HTML redirect on page load

I need one of my website pages to instantly redirect to another upon loading. The refresh HTML command does not work, as it does not check whether or not a certain url is being loaded. Also javascript will work too.
You can wait for a load event with JavaScript and use one of either:
window.onload = function() {
// similar behavior as clicking on a link
window.location.href = "http://stackoverflow.com";
}
or
window.onload = function() {
// similar behavior as an HTTP redirect
window.location.replace("http://stackoverflow.com");
}
Source: How to redirect to another webpage?
Just add a meta tag in the head section of your HTML like this:
<html>
<head>
<meta http-equiv="refresh" content="0;url=http://redirect-to-this-page.com" />
<title></title>
</head>
<body></body>
</html>

How to redirect and return back to same page after a download

I redirected to download page (I used window.location() or window.location.href() or replace()), but after download happens it should again come back to same page. I tried using setTimeout, but in vain. Another thing I dont have a chance to write redirect in download.php.
Is there any solution for this requirement.
Thanks in advance...
Here is my sample code...
<html>
<head>
<meta http-equiv="refresh" content="5; URL=index.php">
<script type="text/javascript" language="JavaScript">
function doSomething(color)
{
//do something nice with params
document.body.style.background = color;
//alert('Hi......');
/*global window */
/*window.location = 'http://all-free-download.com/free-photos/in_love_cosmos_flower_garden_220378_download.html';*/
window.location.href = 'http://all-free-download.com/free-photos/in_love_cosmos_flower_garden_220378_download.html';
/*return false;*/
//header("location:javascript://history.go(-1)");
window.history.back(-1);
window.onload = function() { setTimeout("redirectPage()",3000);
/*return false;*/
window.location.replace("http://google.com");
document.body.style.background = red;
window.setTimeout(redirectPage(), 500);
}
function redirectPage(){
window.location='http://google.com';
}
function download(){
var url = 'http://all-free-download.com/free-photos/in_love_cosmos_flower_garden_220378_download.html';
var htm = '<iframe src="' + url +'" onload="downloadComplete()"></iframe>';
document.getElementById('frameDiv').innerHTML = htm;
}
</script>
</head>
<body>
This page does call a JavaScript function when the page is loaded,
without using the onload() event call.
<script type="text/javascript" language="JavaScript">
doSomething('blue');
</script>
</body>
</html>
You can go back a page (if it was the last page) by doing:
history.back();
Or store the page URL in sessionStorage (or localStorage) and use window.location.href() on the HTML5 web storage variable. If you move through multiple pages.
Although if the page download.php is a completely different page out of your control then there is nothing you can do. Once you leave a page, the code on that page is gone, and you can't do anything on other pages (imagine the security issues if you could). In that case your best best would be to just open the download page in a new tab.

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
}

Categories

Resources