I am facing a problem that I am sure is pretty common. I found many solutions to this problem, and they all have their pros and cons. I'll post what I found here (which I believe will be useful to others), and I hope you'll point me in the right direction.
Essentially, this is my scenario:
- I have a webpage in PHP:
http://example.com/page_with_content_a_or_b.php
. - This page returns
Content A
when no POST parameters are specified, andContent B
if there are. - Assume a user connects to my page typing the previous URL in her browser (a GET request).
- My server returns the page with
Content A
. - The user's web browser, via JavaScript, decides to replace
Content A
withContent B
.
The question: How does the JavaScript replace the contents?
Well, as I've said, I've been looking for different solutions, but none seems perfect.
In order to discuss each possible solution, let me introduce you the resulting HTML code of each version:
HTML of Content A
<html>
<head>
<link rel="stylesheet" type="text/css" href="style_A.css">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="gallery-animator.js"></script>
</head>
<body>
<div class="gallery"><!-- images here --></div>
<p>Content A</p>
<script type="text/javascript" src="content-b-loader.js"></script>
</body>
</html>
HTML of Content B
<html>
<head>
<link rel="stylesheet" type="text/css" href="style_B.css">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="gallery-animator.js"></script>
</head>
<body>
<div class="gallery"><!-- images here --></div>
<p>Content B</p>
</body>
</html>
Differences between both versions
As you can see, in the example both versions are quite similar, but not identical. In general, these are the differences I might encounter:
- All or some or none imported stylesheets may be different.
- All or some or none imported javascripts may be different.
- There might be differences with inline stylesheets and/or javascripts.
- The content is different, but it may differ a little bit only or be completely different.
Content B
does not includes the script for loading itself (last script inContent A
).
Possible Solutions
Replacing Content with document.open(), document.write(), and document.close()
The first solution I implemented is the following:
content-b-loader.js (option 1)
$(document).ready(function() {
$.ajax({
type: 'POST',
url: window.location.href,
data: { load_content_b: 'true' },
success: function( html ) {
document.open();
document.write(html);
document.close();
}
});
});
Apparently, the solution works properly. However, there are situations in which I have problems. In my example, for instance, both contents load a script named gallery-animator.js
. Assuming this script is the following:
gallery-animator.js
var galleryInterval = setInterval(function() {
// Fade out current image and fade in the next one
$("body > div.gallery > img")...
}, 5000);
after executing the script in content-b-loader.js
there are two timeouts animating the gallery. As a result, the animation looks like a mess (two images moving at the same time, or not working at all).
It looks like the sequence document.open()
, document.write(html)
, and document.close()
does not stop and replace the original scripts.
Redirecting with POST data (using a form)
Another solution is doing a redirection described in this previous question. The solution works like a charm: on the one hand, I load the URL I need to load with the required POST data, which means I'll get Content B
, and on the other hand, Content B
is loaded in a "new page", which means that the scripts loaded by Content A
are no longer there.
The problem here? If I refresh the page with Content B
, I get a warning stating that "POST data is about to be resubmitted". This is undesirable, because it looks confusing for the user (I don't want her to know she had been redirected to a new page).
I know there's a solution called PRG (Post-Redirect-Get) which avoids this particular issue. However, it requires Content B
to be accessible using a GET request (using GET params or COOKIES, neither of which I can use).
Using iframes
The last solution I've found is also interesting. Basically, it hides (or empties) the body from Content A
, adds an iframe in the page, and loads Content B
inside it:
content-b-loader.js (option 3)
$(document).ready(function() {
$.ajax({
type: 'POST',
url: window.location.href,
data: { load_content_b: 'true' },
success: function( html ) {
$("body").css('', ''); // Remove all paddings and margins
$("body").empty();
$("body")append('<iframe id="content" seamless="seamless"' +
'src="anchor.html"></iframe>');
// Initialize vars in anchor.html and call the redirect functions
document.getElementById('content').contentWindow.url = window.location.href;
document.getElementById('content').contentWindow.options = {
load_content_b: 'true'
};
document.getElementById('content').contentWindow.redirect();
}
});
});
anchor.html
This page implements the second solution (it uses a POST redirect).
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.redirect.min.js"></script>
<script type="text/javascript">
var url;
var options;
function redirect(){
$().redirect(url, options, 'POST');
}
</script>
</head>
<body></body>
</html>
By making the iframe as big as the window view, I can show the alternative content. If the user refreshes the webpage, the page that is refreshed is the "container" page (the one that originally had Content A
), so no warnings appear at all.
The problems I am facing with this solution, however, are:
- Users can disable iframes. How do I detect whether iframes are enabled or disabled?
- When the user clicks a link in the frame (or submits a form), the "new page" is opened inside the iframe. This is not what I want: I want it to be opened in the main window. How do I do this? I know that there is the
base
directive for links... but what about forms? And JavaScript code that performs a redirection? - Does everything work properly inside iframes? Responsive themes, javascripts, ... As far as I can tell, they do, but I ignore whether users can limit what iframes can do.
TL;DR - Conclusions
I have a page http://example.com/page_with_content_a_or_b.php
. The page returns Content A
when accessed using a GET request, and returns Content B
when accessed using POST. When user types the URL, she gets Content A
, and Content B
is loaded using JavaScript.
All solutions entail problems:
- With document.open(), document.write(), document.close(), scripts get messed.
- With POST redirections, refreshing the page popups a warning
- With iframes, they are not always available, and I am somehow "stucked" inside them.
Any ideas? Am I missing something? Is there a preferred way to do what I'm trying to do?
Thank you very much!