admin管理员组

文章数量:1414614

I'm having trouble with an iframe-related issue.

I have a document (parent) with an iframe (child). If the parent document calls a function in the child which changes the childs url using window.location to a relative url, that url bees relative to the parent document. Let me illustrate.

Parent document: /test/parent.html

Child document: /projects/child.html

Child code:

function moveOn(){
    window.location.href = "newPage.html";
}

Parent code:

childDocument.contentWindow.moveOn();

Result: Child document tries to access /test/newPage.html instead of /projects/newPage.html

Is there any way of fixing this from the parent? I am in a situation where I can't make changes in the child document code, only in the parent.

Thanks, Nik

Edit:

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}

I'm having trouble with an iframe-related issue.

I have a document (parent) with an iframe (child). If the parent document calls a function in the child which changes the childs url using window.location to a relative url, that url bees relative to the parent document. Let me illustrate.

Parent document: /test/parent.html

Child document: /projects/child.html

Child code:

function moveOn(){
    window.location.href = "newPage.html";
}

Parent code:

childDocument.contentWindow.moveOn();

Result: Child document tries to access /test/newPage.html instead of /projects/newPage.html

Is there any way of fixing this from the parent? I am in a situation where I can't make changes in the child document code, only in the parent.

Thanks, Nik

Edit:

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Feb 17, 2010 at 12:44 NikNik 311 silver badge3 bronze badges 5
  • Huh? Are you 10000% sure this happens the way you describe? That would be most odd. If you call moveOn from within the child window, it definitely redirects to a different URL? – Pekka Commented Feb 17, 2010 at 12:50
  • .. and wele to SO by the way. – Pekka Commented Feb 17, 2010 at 12:51
  • Thanks!. See my ment below with properly formatted code. – Nik Commented Feb 17, 2010 at 12:59
  • I'm having exactly the same problem, except in reverse (I want the child to control the parent relative to the parent's url). It's exactly the same situation, though. – aaaidan Commented Apr 23, 2012 at 23:42
  • This "apparently surprising" behaviour happens because the code is running in the context of the parent, which means any relative urls are interpreted relative to the parent. Actually makes sense, in some ways. If it worked the other way, people would describe it as confusing, too. :) – aaaidan Commented Apr 23, 2012 at 23:47
Add a ment  | 

3 Answers 3

Reset to default 4

Finally, a full solution!

childDocument.contentWindow.setTimeout( childDocument.contentWindow.moveOn, 0 );

This asks the child document to execute the given function (moveOn) in zero milliseconds, and it is executed in the context of the child, even in Internet Exploder.

Booyah.

The HTML spec says:

When the [location property is set], the [browser] must resolve the argument, relative to the entry script's base URL, and if that is successful, must navigate the browsing context to the specified url.

One (hacky) way to get the behaviour you're after is to edit the pathname property of the location directly: effectively implementing the resolution of the relative url yourself.

In your case, you'd edit url "manually", using your child's existing url.

Dotdot solution

One "clever" way to do that is by appending a slash to turn the filename into a "directory", then erasing it with a "dotdot", followed by the relative url you want.

childDocument.contentWindow.location.pathname += "/../newPage.html";

(This code could also work within the child, but you mentioned you can't change the child code.)

Check out how this works.

The path starts as
/projects/child.html

Then you append to it, to get
/projects/child.html/../newPage.html

The browser resolves this to
/projects/newPage.html

Unfortunately, I imagine this won't be a perfect solution to you. Sounds like each of the "child" pages contain hard-coded links to the next page in the chain, which could be any page. Getting the "next" relative url for any given child page would require cooperation from the child.

If the child pages are named in a predictable way, and you know the total number of pages, and you know the base url of the child directory, you could have the parent control the child correctly. That's a lot of ifs.

Sidenote: I'm looking into a more elegant, robust solution. Fingers crossed.

Aha. I've found the baseURI property. Now we're talking.

The fundamental problem is that the baseURI of the document which is executing the code (the parent) is set to the parent's location. You want to set the baseURI of the page to be the same as the child's location before you change it's location, so that the relative url is resolved in the context of the child.

In short, it would be great to say:

var originalURI = document.baseURI; // store for setting back after the move
document.baseURI = childDocument.location; // setting parent's baseURI (NO EFFECT!)
childDocument.contentWindow.moveOn();
document.baseURI = originalURI; // restore original baseURI

Unfortunately, the baseURI property is read only. Fortunately, its value is taken from the <base> tag, which you can alter with script. You can get the functionality you want for a given child by setting the parent's base tag to refer to the childUrl:

<head>
<base href="/path/to/child.html" />
</head>

Unfortunately, this makes any relative links in your parent relative to the child, which is not what you want. We need to set this just after clicking the link, and set it back after the child has been told to moveOn().

If you include an empty <base /> tag in your parent's <head>, it will not effect the baseURI by default. So when you want to execute the moveOn() function in the child, you can say something like:

var baseElement = document.getElementsByTagName("base")[0];

// adopt the child's location as baseURI
baseElement.href = childDocument.location; 

childDocument.contentWindow.moveOn();

// revert back to the parent's original baseURI
baseElement.removeAttribute("href"); 

(Hope this helps somehow - two years on... ha)

Edit:

Once again Internet Exploder is the party pooper. It seems that changes to any tag after load are not honoured. So unless you don't have to support IE (HA!), this solution won't work unless you're happy to hard code the child's location into the parent's tag. Again, those are big ifs.

本文标签: javascriptUsing relative url for windowlocation in child iframeStack Overflow