title: Move entire document into iframe
body: <p>I'm adding a chat feature to a couple of our websites. The chat will connect users with people at our help desk to help them use the websites. Our help desk folks want the chat window to appear like a tab on the side of the page and slide out, rather than popping up in a new window. However, I want to allow the user to navigate around the site without losing the chat.</p>
  
  <p>To do this, I've been trying to move the entire page into an iframe once the chat starts (with the chat outside the iframe), so the user can navigate around the site within the iframe without losing the chat.</p>
  
  <p>I used <a href="https://stackoverflow.com/questions/18259499/move-the-whole-document-into-an-iframe">this answer</a> to get started, and that works great visually. However, some of the javascript in the background breaks.</p>
  
  <p>One of the sites is ASP.NET web forms. The other is MVC. I've been working with the web forms one first. Stuff like calling __doPostBack breaks once the page is moved into the iframe since the javascript context is left behind.</p>
  
  <p>Once the user clicks on a link (a real link, not a __doPostBack) and the iframe refreshes, then everything works perfectly.</p>
  
  <p>How I see it, I have a few options:</p>
  
  <ol>
  <li>Copy all javascript variables from window.top into the iframe somehow. Hopefully without having to know all the variable names. I tried <code>this.contentWindow.__doPostBack = window.top.__doPostBack</code>, which works, but other variables are missing so it ultimately fails:</li>
  <li>Somehow switch the iframe's context to look at the top window context, if that's even possible? Probably not.</li>
  <li>Another thought was to not move the page into an iframe right away, but to wait until the page changes and then load the new page into a new iframe. But I'm not sure how to hook into that event and highjack it.</li>
  <li>Something else?</li>
  </ol>
  
  <p>These are sites for use by our employees only, so I only have to support IE11 and Chrome.</p>
  
  <p><strong>Update:</strong></p>
  
  <p>Thanks to LGSon for putting me on the track of using the target attribute (so I can use approach #3). Below is what I ended up doing. When I pop out the chat, I call <code>loadNextPageInIframe()</code>. I'm using jQuery here since we already use it on our site, but everything could be done without. I set the target on all links that don't already have a target pointing to another frame or _blank. I left _parent out, but I don't think we use it anyway.</p>
  
  <p>I have a reference to my chat window div in a global variable called 'chatwindow'.</p>
  
  <p>There still could be some cases where this doesn't work, such as if there is some javascript that sets window.location directly. If we have anything in our sites that does this, I'll have to add a way to handle it.</p>
  
  <pre><code>function loadNextPageInIframe() {
      var frame = $("&lt;iframe id=\"mainframe\" name=\"mainframe\" /&gt;").css({
          position: "fixed",
          top: 0,
          left: 0,
          width: "100%",
          height: "100%",
          border: "none",
          display: "none"
      }).appendTo("body");
  
      $("form, a:not([target]), a[target=''], a[target='_top'], a[target='_self']").attr("target", "mainframe");
  
      var firstload = true;
      frame.load(function () {
          //Runs every time a new page in the iframe loads
          if (firstload) {
              $(frame).show();
              //Remove all elements from the top window except the iframe and chat window
              $("body").children().not(frame).not(window.top.chatwindow).remove();
              firstload = false;
          }
          //Make the browser URL and title reflect the iframe every time it loads a new page
          if (this.contentWindow &amp;&amp; this.contentWindow.location.href &amp;&amp; window.top.location.hostname === this.contentWindow.location.hostname &amp;&amp; window.top.location.href !== this.contentWindow.location.href) {
              var title = this.contentDocument.title;
              document.title = title;
              if (window.top.history.replaceState) window.top.history.replaceState(null, title, this.contentWindow.location.href);
          }
      });
  }
  </code></pre>