2

I'm having problems with history object and iframes in javascript/html5. I wrote a simple project to describe my problem:

http://dktest.evermight.com/

It's a page with an iframe and a next button. Every time you click next, it loads a new page with an incrementing counter. However, clicking the browser back button doesn't do what I want it to do. Let me explain the problem by breaking this post up into the following sections:

  1. What I'd like to achieve
  2. Undesired results in current project
  3. Post all my code

1. What I'd like to achieve

I want the user to:

  1. Open a new window and go to http://dktest.evermight.com/
  2. Click next page and see a redbox fade in, and to see the url http://dktest.evermight.com/count.html?count=0 appear in both the iframe AND the browser's address bar
  3. Click next page again and see http://dktest.evermight.com/count.html?count=1 in the iframe and browser's address bar
  4. Click browser's back button ONCE and see http://dktest.evermight.com/count.html?count=0 in both the iframe and the browser's address bar
  5. Click browser's back button ONCE and see http://dktest.evermight.com/ in the browser's address bar AND see the red box fade out

2. Undesired results in current project

With my code at http://dktest.evermight.com/, it's currently not performing steps 4 and steps 5 correctly. When I perform step 4, the iframe shows http://dktest.evermight.com/count.html?count=0 but the browser address bar shows http://dktest.evermight.com/count.html?count=1. I have to press the browser's back button again to make the browser address bar show http://dktest.evermight.com/count.html?count=0. When I perform step 5, the red box fades out which is great, but the address bar is still showing http://dktest.evermight.com/count.html?count=0. I have to press back again to make the address bar show http://dktest.evermight.com/.

3. Post all my code

My code is pretty straight forward. You can view source on http://dktest.evermight.com/. I will also post here for convenience.

index.html

<!DOCTYPE html>
<html>
<head>
   <title></title>
   <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
   <script type="text/javascript">
var count=0;
function clicknext()
{
   $('#container').fadeIn();
   $('#iframe').attr('src','count.html?count='+count.toString());
   $('html title').html(count);
   history.pushState({blahblah:'whatgoeshere?'},'i dont know what goes here either','http://dktest.evermight.com/count.html?count='+count);
   count++;
}
function hideContainer()
{
   $('#container').fadeOut();
      var closeurl = 'close.html';
      if($('#iframe').attr('src') != closeurl )
      $('#iframe').attr('src', closeurl);

}

$(document).ready(function(){
   hideContainer();
});
   </script>
</head>
<body>
<div id="container" style="display:none; background:red;">


        <!-- IMPORTANT 
            When DOM first created, the iframe.src MUST BE initialize.html
            I have some code that I need to fire on that page before the rest 
            of this document starts
        -->
        <iframe id="iframe" src="initialize.html"></iframe>
</div>
        <input type="button" onclick="clicknext()"; value="next page" />
</body>
</html>

close.html

<!DOCTYPE html>
<html>
        <script type="text/javascript">
                parent.hideContainer();
        </script>
</html>

count.html

I CAN NOT modify the contents of count.html. In my real project, count.html is actually a youtube video, which is on a server I can't directly access.

<html>
        <body>Youtube video at url <script type="text/javascript">document.write(location.href);</script></body>
</html>

initialize.html

Perform application specific functionality

Can anyone correct my code to achieve the results of step 4 and step 5 as described in section 1?

UPDATE Ok, I'm appreciating the problem a bit more based on some experiments I'm doing.

Experiment 1: I tried changing the line:

$('#iframe').attr('src','count.html?count='+count.toString());

to

$('#iframe')[0].contentWindow.location.replace('count.html?count='+count.toString());

This allowed me to perform step 4 correctly. Apparently, contentWindow.location.replace() will not create an entry in the history object. However, this caused some other issues related with the contents of count.html, which is actually a page to youtube/vimeo content. The youtube/vimeo content REQUIRES that you load information via the attr('src') approach instead of .contentWindow.location.replace(). So perhaps the solution is to find a way to make attr('src') NOT create an entry with the history object?

Experiment 2 Another possible solution I tried was changing the order of the attr('src') and history.pushState() call. I tried calling attr('src') first then history.pushState() second, and also history.pushState() first then attr('src') second. But in both cases, when I push the browser's back button, it is the iframe content that goes back first. So there's no way for me to capture pass myself a message via the history object to do a "double back", since information in the history object is available LAST in the sequence of events.

Experiment 3 I also tried working with History.js. It did not do anything to solve my problems above. From what I could tell, it worked exactly like the regular history object.

Does anyone have any thing else I can try? Or suggest modifications to any of the experiments above? I'm going to explore Experiment 1 further as a separate stack overflow question.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
John
  • 32,403
  • 80
  • 251
  • 422

2 Answers2

2

I create a new iframe and destroy the iframe when loading new content. That solves the history issues.

John
  • 32,403
  • 80
  • 251
  • 422
0

I know this is a history problem but if you are still open to other possibilities, I think jquery-pjax is actually more suitable for what you are trying to do.

UPDATE I think this should work.

count.html

 <div id="pjax-container">
    <a id="pjax" data-pjax href="#">Next Page</a>
 </div>

javascript

 // get URL parameter (count): http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
 function getURLParameter(name) {
     return decodeURI(
        (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
     );
 }

 $(document).on('pjax:beforeSend', function() {
     // your fading code goes here
 })

 $(document).on('pjax:complete', function() {
     // fade out
     // and then modify the anchor's href with something like   
     var new_count = getURLParameter('count') + 1;          
     $('a#pjax').attr('href', 'count.html?count=?' + new_count); 
 })

 // where the pjaxed content should go
 $(document).pjax('a[data-pjax]', '#pjax-container')
Lim H.
  • 9,870
  • 9
  • 48
  • 74
  • I am open to using jquery-pjax. Is it easy for you to post sample solution to my problem above using jquery-pjax? – John Feb 06 '13 at 05:28
  • sure. Give me a moment I'll type up an example. – Lim H. Feb 06 '13 at 05:38
  • I've updated my answer. It's very rudimentary but that's how I'd go about your problem with pjax. – Lim H. Feb 06 '13 at 06:05
  • OK, i'll have to do more research because i'm not sure what's going on. Also i can not modify count.html, because that's on a 3rd party server. – John Feb 06 '13 at 08:35
  • Hmmm maybe you can add a data-attribute somewhere and store it there, like inside of
    – redconservatory Feb 06 '13 at 12:01