I'm trying to create a javascript file with functions that allow me to redirect to another page. But it is not redirected. This is my code:
on my functions.js
function openUrl(url) {
window.location = url;
}
on my php page
<script>openUrl('<?=$my_url?>');</script>
<script src="./functions.js" type="text/javascript"></script>
Order matters
You call openUrl, which (if you have looked at the Console in your browser's developer tools) is throwing a ReferenceError because it isn't defined.
Then you load your functions.js which defines openUrl (but by then it is too late).
That said, if you are generating an HTML document which immediately goes to a new URL with JS then you should probably be simply issuing a 301 or 302 redirect response instead of an HTML document in the first place.
switch these two lines
<script src="./functions.js" type="text/javascript"></script>
<script>openUrl('<?=$my_url?>');</script>
This question already has answers here:
Using iframe with local files in Chrome
(3 answers)
Closed 8 years ago.
I have a requirement to develop a web app that is to be accessed locally and offline. As part of the design an iframe is used to swap out content as and when needed. The trouble is that when accessed locally the script works in FF 32 and IE 11 but not in Chrome 38. All running on Windows 7 SP1 64-bit.
Further, when accessed from a server, the same script works in Chrome, FF and IE. I have a hunch that it could be caused by a bug in Chrome. Nevertheless, I would like to know if there is anything wrong with my script. I have provided them here :
index.html
<body>
<p>This example demonstrates how to assign an "onload" event to an iframe element.</p>
<iframe id="iFrame" name="iFrame" height="500px" width="500px" src="about:blank"></iframe>
<p id="demo"></p>
<button id="swap" onclick="swap()">SWAP</button>
<script>
function swap() {
document.getElementById("iFrame").src = "child.html";
}
function myFunction() {
document.getElementById("demo").innerHTML = "Iframe is loaded.";
}
window.onload = myFunction();
</script>
</body>
child.html
<body>
<h1>This is an extra page...</h1>
<button onclick="next()">NEXT</button>
<script src="worker.js" type="text/javascript"></script>
</body>
grandchild.html
<body>
<h1 id="header"></h1>
<button onclick="prev()">PREV</button>
<script>
window.onload = function () {
init();
};
</script>
<script src="worker.js"></script>
</body>
worker.js
function next() {
window.frameElement.src = "grandchild.html";
}
function prev() {
window.frameElement.src = "child.html";
}
function init() {
var iFrame = window.frameElement;
var frameDocument = (iFrame.contentWindow || iFrame.contentDocument);
if (frameDocument.document)frameDocument = frameDocument.document;
frameDocument.getElementById("header").innerHTML = "This is from the script!!";
}
It is obvious that window.frameElement is undefined. I'm a newbie to web development. Any help will have my gratitude.
After digging around a lot, I've learned that this is a feature of Chrome/Chromium. For security purposes all local content is blocked within an iframe. There are two possible solutions to this problem :
a) As such to use an iframe one must access content from a web server. This can be accomplished by serving the entire app from a server[online] or bundling the app as a Node.js app with additions.
b) Another possible solution is to replace the iframe with a possible alternative, though not one solution seems simpler than using an iframe, IMHO.
Since my requirement is to deploy this web app locally from a CD/DVD, I find the Node.js solution attractive as this implies a possible Node-webkit deployment too.
I'm trying to send this command:
document.body.innerHTML = document.body.textContent;
like in this script:
var iframeBody = $(window.my_frame.document.getElementsByTagName("body")[0]);
iframeBody.append($("<h1/>").html("Hello world!"));
in this jsfiddle
HTML:
<iframe id='my_frame' src="http://www.sec.gov/Archives/edgar/data/1168960/0001052918-13-000257.txt"></iframe>
nevertheless it does not executes; anyone knows why?
cheers
You have a Same Origin Policy problem. You can't access the contents of an iframe that resides on a different domain to yours.
In the fiddle, you also didn't include jQuery.
this does the trick http://jsfiddle.net/Paulpro/fDN7t/
<div id="example"></div>
$('#example').load('http://www.sec.gov/Archives/edgar/data/1168960/0001052918-13-000257.txt');
In order to solve Cross Domain security woes of JavaScript, I am implementing the following method
On Domain [ abc.com ]
On domain abc.com I have a page called main_page.html. Its code is as follows -
<script>
function SendMsg(id)
{
frames["invisible_iframe"].location = "http://xyz.com/invisible_iframe.html#"+id;
}
</script>
<body>
<input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
<iframe src="ttp://xyz.com/visible_iframe.html" name="visible_iframe" height="250" width="500"></iframe>
<iframe name="invisible_iframe" height="0" width="0" style="display:none;"></iframe>
</body>
On Domain [ xyz.com ]
On domain xyz.com I have a page called visible_iframe.html. Its code is as follows -
<script>
function Hi()
{
alert("Hi there!");
}
</script>
<body>
<h1>Visible iFrame on xyz.com
<iframe name="d2_invisible_iframe" id="d2_invisible_iframe" class="iFrame" src="http://xyz.com/invisible_iframe.html" height="310" width="520"></iframe>
</body>
Now I want to access the function Hi() from invisible_iframe.html (which is on the same domain)
The code of invisible_iframe.html is as follows
<script>
var sActionText = "";
function CheckForMessages()
{
if(location.hash != sActionText)
{
sActionText = location.hash;
var sAction = "";
var oSplitActionText = sActionText.split("#");
sAction = oSplitActionText[1];
if (sAction == "Test")
{
parent.Hi();
}
}
}
setInterval(CheckForMessages, 200);
</script>
<body>
<h1>Invisible iFrame on xyz.com</h1>
</body>
I am using hidden iFrame in visible_iframe.html because I don't want the URL of visible_iframe.html to change.
Now I expect when the button on main_page.html is clicked, I'd get alert message. But that doesn't happen. In firefox it says - Permission denied to access property 'Hi'
The strange thing is when I put parent.Hi(); outside CheckForMessages() function, the Hi() function can be accessed and alert box is shown.
What should I do to resolve this ?
Why not using easyXDM? This library should make your life really easy and help to avoid the security limitations when dealling with cross domain issues. Specially if you have control over the two domains.
easyXDM is a Javascript library that enables you as a developer to
easily work around the limitation set in place by the Same Origin
Policy, in turn making it easy to communicate and expose javascript
API’s across domain boundaries.
[This is one of the best and easy to use APIs] available for Cross Domain Communication between web applications.
easyXDM is easy to use, light weight, flexible, writing good quality code etc. I strongly think if you are going to continue with cross domain scenario, then you should adapt a robust cross domain apis such as easyXDM.
[easyXDM vs PostMessage Transport?]
easyXDM will use the PostMessageTransport method if this feature is enabled by the browser such as (IE8+, Opera 9+, Firefox 3+, Safari 4+,Chrome 2+) on the other side it will use different transport methods for the un supported browsers such as (Firefox 1-2 - using the FrameElementTransport) other transport methods will be used as needed such as FlashTransport, NameTransport, and HashTransport).
This clearly makes easyXDM superior in terms on browser support specially the old browsers.
To demonstrate cross-domain access using easyXDM (Domain1 [abc.com] calls a method on a remote domain [xyz.com]):
*On Domain [ abc.com ] - main domain*
<script type="text/javascript">
/**
* Request the use of the JSON object
*/
easyXDM.DomHelper.requiresJSON("../json2.js");
</script>
<script type="text/javascript">
var remote;
window.onload = function(){
/**
* When the window is finished loading start setting up the interface
*/
remote = new easyXDM.Interface(/** The channel configuration */{
/**
* Register the url to hash.html, this must be an absolute path
* or a path relative to the root.
* #field
*/
local: "/hash.html",
/**
* Register the url to the remote interface
* #field
*/
remote: "http://YOUR.OTHER.DOMAIN/YOUR_APPLICATION/YourRemoteApplication.html",
/**
* Register the DOMElement that the generated IFrame should be inserted into
*/
container: document.getElementById("embedded")
}, /** The interface configuration */ {
remote: {
remoteApplicationMethod: {},
noOp: {
isVoid: true
}
},
local: {
alertMessage: {
method: function(msg){
alert(msg);
},
isVoid: true
}
}
},/**The onReady handler*/ function(){
/**
* Call a method on the other side
*/
remote.noOp();
});
}
function callRemoteApplicationMethod(Value1, Value2){
remote.remoteApplicationMethod(Value1, Value2, function(result){
alert("Results from remote application" + result);
});
}
</script>
In the body
<input type="button" onclick="callRemoteApplicationMethod(3,5)" value="call remoteApplicationMethod on remote domain"/>
Now on your remote domain side you need to define your remote client as follows
*On Domain [ xyz.com ] - Remote domain*
This should go into the page YOUR_APPLICATION/YourRemoteApplication.html
<script type="text/javascript">
/**
* Request the use of the JSON object
*/
easyXDM.DomHelper.requiresJSON("../json2.js");
</script>
<script type="text/javascript">
var channel, remote;
/**
* When the window is finished loading start setting up the channel
*/
window.onload = function(){
/**
* When the channel is ready we create the interface
*/
remote = new easyXDM.Interface(/** The channel configuration*/{}, /** The configuration */ {
remote: {
alertMessage: {
isVoid: true
}
},
local: {
remoteApplicationMethod: {
method: doSomething(value1, value2){
// do somethigs with values
return "i'm return value from remote domain";
}
},
noOp: {
isVoid: true,
method: function(){
alert("Method not returning any data");
}
}
}
});
}
</script>
I suppose there is no need to suport old browsers, right?
You can use window.postMessage in modern browsers to support cross-origin communication.
You won't believe the cause. On main_page.html (abc.com) you define two iframes but you don't close them (missing </iframe>). Now there are two cases:
Case 1:
iframes are independent so your main_page.html code should be
<iframe src="http://xyz.com/visible_iframe.html" ...></iframe>
<iframe src="http://xyz.com/invisible_iframe.html" ...></iframe>
and the javascript call from invisible_iframe.html should be
parent.frames["visible_iframe"].Hi();
Case 2:
iframes are parent and child so main_page.html code should be
<iframe src="http://xyz.com/visible_iframe.html" ...></iframe>
visible_iframe.html code sould include
<iframe src="http://xyz.com/invisible_iframe.html" ...></iframe>
and the javascript call from invisible_iframe.html should be
parent.Hi();
That's all. The choice is yours.
Assuming your onlcick works on your input (just a typo there): from invisible_frame, you should address visible_frame's Hi() with parent.frames['visible_frame'].Hi().
For now, parent.Hi() tries to access a Hi() located on abc.com's page (as it is the frame's parent), so you're poked with the hard stick of Same Origin Policy.
Hope this helps and works ;)
Try creating these three files:
http://abc.com/main.html:
<!DOCTYPE html>
<html>
<head>
<script>
function SendMsg(id) {
window.frames.invisible.location = 'http://xyz.com/invisible.html#' + id;
}
</script>
</head>
<body>
<input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
<iframe src="http://xyz.com/visible.html" name="visible" height="250" width="500"></iframe>
<iframe name="invisible" height="0" width="0" style="display:none;"></iframe>
</body>
</html>
http://xyz.com/visible.html:
<!DOCTYPE html>
<html>
<head>
<script>
function Hi() {
alert('Hi there!');
}
</script>
</head>
<body>
<h1>Visible on xyz.com</h1>
</body>
</html>
http://xyz.com/invisible.html:
<!DOCTYPE html>
<html>
<head>
<script>
var sActionText = "";
function CheckForMessages() {
if (location.hash != sActionText) {
sActionText = location.hash;
var sAction = "";
var oSplitActionText = sActionText.split("#");
sAction = oSplitActionText[1];
if (sAction == "Test") {
parent.frames.visible.Hi();
}
}
}
setInterval(CheckForMessages, 200);
</script>
</head>
<body>
<h1>Invisible on xyz.com</h1>
</body>
</html>
Notice that the frame structure is:
main
/ \
/ \
visible invisible
And so if you need to access visible from invisible, you need to go:
parent.frames.visible.Hi()
Moving forward, I suggest using easyXDM or the jQuery postMessage plugin for cross-domain communication instead of reinventing the wheel.
There is a reason it is not letting you access the function because of the same origin policy. It would cause real security issues if you could.
CORS (Cross-Origin Resource Sharing) or window.postMessage (ref: Docs on MDN or another simple postMessage example) are definitely worth investigating if you don't care about IE7 support; you could also use a postMessage shim for older IE browsers.
However, I'll stick with an iframe solution in an attempt to more precisely answer your question.
Unfortunately you should not be able to access the parent (window scope) properties/methods from a cross domain iframe. However you can access window scopes via iframes on the same domain ...at any depth. Thus, one solution is to leverage vertical iframe tunnels.
If you create three html documents:
Top level - abc.com
<script>
function sendMsg( id ) {
frames["invisible_iframe"].location = "//xyz.com/mid_level.html#" + id;
}
window.ACTIONS = {
Test: function() {
alert("hello");
// This action could also start an interaction with another
// visible iframe by setting a hash, etc
}
};
</script>
<input type="button" id="Test" value="Call iFrame" onclick="sendMsg(this.id);">
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//xyz.com/mid_level.html"></iframe>
Mid Level - xyz.com
<script>
function sendMsg( id ) {
frames["invisible_iframe"].location = "//abc.com/low_level.html#" + id;
}
var sActionText = "";
function checkForMessages() {
if(location.hash != sActionText) {
sActionText = location.hash.replace(/^#/, "");
location.hash = "";
sendMsg(sActionText);
}
}
setInterval(checkForMessages, 20);
</script>
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//abc.com/low_level.html"></iframe>
Low Level - abc.com
<script>
function runActionInTop( action ) {
try {
window.top.ACTIONS[action]();
} catch ( err ) {
// Bad action!
}
}
var sActionText = "";
function checkForMessages() {
if(location.hash != sActionText) {
sActionText = location.hash.replace(/^#/, "");
location.hash = "";
runActionInTop(sActionText);
}
}
setInterval(checkForMessages, 20);
</script>
These three iframes can communicate - the first and third can communicate directly and the second indirectly (via hash in this example).
I know this is a variation from what you were originally trying to show with the "visible iframe". I wanted to focus on illustrating the layering necessary for the cross-site communication. If you still need the visible iframe, you could add communication hooks at the top level and also send additional information (in the hash) back from the middle frame to the lowest frame (the lowest frame could then communicate the information directly back to the top page).
Yes, I know this is convoluted - that is one of the reasons why CORS and postMessage exist :)
I've also changed a few minor aspects of your original code that I think are worth pointing out:
Using // instead of http:// means that this system will work on either http or https.
Some browsers (I believe I first ran into this with Safari 3) may not actually load the iframe with display:none; setting the frameborder attribute and visibility:hidden will keep the iframe from being visible.
Some browsers will load about:blank (or a similar page) if you do not specify the iframe src attribute in the markup. On https pages, this can cause insecure content warnings to be thrown in IE.
An alternative, Proxying.
In server-side grab the external file and echo it back. Now it is on your domain so no issues.
for example in php
<?php
$external-site = file_get_contents('http://xyz.com/');
echo $external-site;
?>
I think I would delete any iframes and use jsonp maybe with a library.
1. No Cross-domain errors
2. You could get data as objects (easy to play with 'em
3. You could even get JS code that u could parse.
4. Would be even mobile ready ( iframes are last century solutions... )
But then well maybe you are not able to take away the iframes for any reasons, so I advice to use a ready-made library solution.
Goodluck
I am trying to call a javascript function defined in a parent from a child window. I have two files like this:
Parent:
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function foo () {
alert ("Hello from parent!");
}
function doStuff () {
var w = window.open("testa.html");
}
</script>
</head>
<body>
<input type="button" value="open" onClick="doStuff();" />
</body>
</html>
And child:
<html>
<head>
<title>Test A</title>
<script type="text/javascript">
function get() {
window.opener.foo();
}
</script>
</head>
<body>
<input type="button" value="Call Parent" onClick="get();" />
</body>
</html>
I can not, for the life of me, call the function foo from the child process. I thought this should be possible with the window.opener object, but I can not seem to make this work. Any suggestions?
Ensure you are accessing this via http:// so the Same origin policy passes and you can access opener from the child. It won't work if you're just using file://.
Answering Rahul's question:
Every browser can load pages from server or from local filesystem. To load file from local filesystem you should put to the browser the address like this file://[path], where [path] is the absolute path to the file in filesystem (including drive letter on Windows, see http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx for details).
To load file from local HTTP server (if you have one) you should put to address something like this http://localhost:[port]/[path], where [port] is the port where your server is running (default is 80) and [path] is the path of the file relative to the server's document root folder. Document root folder depends on the server configuration.
So, as you see, the same local file can be loaded to the browser in two ways. There is however big difference between these two ways. In the first case the browser doesn't use HTTP protocol to load the file and therefore is missing many things necessary for different mechanisms to work properly. For example AJAX doesn't work with local files, as HTTP response status is not 200, etc.
In this particular example the browser security mechanism didn't get the origin information and was preventing from accessing the parent window.