I'm using a simple .html page to redirect someone to page A if they don't have a cookie. If they do have the cookie I want to send them to page B.
The issue I'm having is someone will get redirected to page A, but when they push the back button on page A, the .js isn't executing on my simple .html page and sending them to page B. Instead, the blank .html page is loading and that's it.
//this function fixed Safari
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
window.onunload = function() {}; // this seems to have fixed Firefox
setTimeout(function() {
if (document.cookie.indexOf("visitedinhour=") >= 0) {
// They've been here before.
window.location = 'https://www.google.com';
} else {
// set a new cookie
document.cookie = "visitedinhour=true; max-age=" + 3600;
window.location = 'https://www.bing.com';
}
}, 200);
What I'd like to happen is someone visits my .html page, is redirected to page A, then click the back button, and are redirected to page B.
UPDATE: Firefox seems to work as intended. Chrome and Safari don't. Chrome goes back to the page before my .html page and Safari still loads the blank .html page.
UPDATE 2: Safari is fixed; Chrome isn't working as intended. When on Bing.com and you click the back button the browser goes to the page it was on before my .html page with this code.
This could be a known issue in Firefox.
Try to set an empty function to be called on window.onunload:
window.onunload = function() { };
This is because Firefox (and Safari, and Opera) keeps the website intact. it does not immediately destroy your page to go onto the next one, which results in a much faster and smoother back/forward page transitions for the user.
Update
This should work for Safari (it will force a reload when page is loaded from bfcache):
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
Update 2:
This code should be compatible with all browsers although you may need to use the above snippets too.
window.addEventListener("pageshow", function (event) {
var historyTraversal =
event.persisted ||
(
// Check if performance not undefined (restored from cache)
typeof window.performance != "undefined" &&
// Check if the back button was used
window.performance.navigation.type === 2
);
if (historyTraversal) {
// Handle page restore and reload the page
window.location.reload();
}
});
Related
I have a page that gets the contents from a servlet. The page gets updated with javascript every minute. When the mobile wakes up (I am using jquery.wakeup-plugin ) and it was 'asleep' for more than 60 secs, I call :
location.reload(true);
or
window.location.href = window.location.href;
First line works for Chrome and Firefox but not for Safari, and the second line doesn't work for Safari and Chrome.
It reloads the page, but the page doesn't update. It shows the content before it went to sleep. After pressing F5 all browsers reload just fine.
Any tips on how to fix the refresh?
var bell_id = $.wakeUp(function(sleep_time) {
if (sleep_time > 59000) {
//location.reload(true); NOT WORKING FOR SAFARI
window.location.href = window.location.href;
$.ignoreBell(bell_id);
}
});
U mean like that?
$(document).ready(function() {
setInterval(function() {
cache_clear()
}, 60000);
});
function cache_clear() {
window.location.reload(true);
// window.location.reload(); use this if you do not remove cache
}
The iOS Safari doesnt't seem to trigger pageshow event in the following situation.
Lets say I have 3 pages
Page A : (has some code code on pageshow event)
Page B
Page C
User navigates from A -> B. Presses the back button. (pageshow triggers fine)
User then navigates to another page could be Page B or Page C. Then presses the back button again. (pageshow doesn't trigger)
On the contrary if the user minimizes and maximizes the window again or switches to another window and back (by pressing the middle button on iPhone) the pageshow event is triggered again.
Everything seems to work fine on Android
window.onpageshow = function(e) {
alert('hello');
}
Did anyone else face it? I spent hours on this thing and couldn't think of a workaround.
Any help would be greatly appreciated.
Hack : This is what worked for me
var myCustomEvent = (navigator.userAgent.match('iPhone') != null) ? 'popstate' : 'pageshow';
$(window).on(myCustomEvent, function(e) {
...
}
For some reason popstate triggers everytime when page state changes in iOS but not in Android.
Try using:
window.onpageshow = function(event) {
if (!event.persisted) {
alert("hello");
}
};
Persisted is false on initial page load, so you can check against it, and if it false, it is your first page load.
The popstate event doesn't seem to work any more, at least for me. I worked out some third-party script on my page was breaking this, but wasn't able to work out which one. I came up with this hack:
addEventListener('pageshow', () => {
history.replaceState({}, document.title, window.location.pathname);
// called on initial load and first back
});
addEventListener('popstate', () => {
// called on all back events
});
In a standard Java / SpringMVC / JSP / jQuery web-app, I'm trying to detect a "Back" (or history.go(-1)) event, in order to refresh (AJAX) a summary component/panel content when I return to a page (where we can change the backend data that is displayed by the summary component).
I tried the following in JavaScript (following some posts on StackExchange re how to achieve this):
<script type="text/javascript">
$(document).ready(function() {
window.onpageshow = function(event) {
console.log("Event:");
console.dir(event);
if (event.persisted) {
alert("non-jQuery - back to page - loaded from bfcache");
} else {
alert("non-jQuery - loaded page from server");
}
};
$(window).on("pageshow", function(event){
console.log("Event:");
console.dir(event);
if (event.originalEvent.persisted) {
alert("jquery - back to page - loaded from bfcache");
} else {
alert("jquery - loaded page from server");
}
});
});
</script>
I am running OpenSUSE Linux and have tried this with FireFox and Chrome (latest versions), but every time the event's persisted attribute is set to false (I can see this in the JavaScript console and by the alerts that pop-up from the above code). By every time, I mean, regardless of whether it was loaded from the server or shown again via the Back button (or a 'Back' link).
My intention was to make an AJAX call to reload the summary component/panel with the updated data from the server if the page was showing via the Back button or history.go(-1) call.
I also tried setting an unload handler (that does nothing) to prevent the page from being put into the bfcache but it still seems to be showing a bf-cached version and the event.persisted (or event.originalEvent.persisted) is set to false.
Is this property managed correctly on Linux? Am I doing something stupid in my code? Any help or ideas would be much appreciated, thanks!
I have found hidden input buttons are not a reliable solution since they may hold the wrong value when the user navigates back to the page and then hits refresh. Some browsers (Firefox) retain input values on refresh so every time the user hits refresh it will refresh again since the input button holds the wrong value. This is a typical scenario for forums (user views a topic, hits the back button to go back to the list of topics, and may continue to hit refresh to check if there are new topics).
As noted by Grégoire Clermont, event.persisted is buggy in chrome (and IE) and this still hasn't been fixed for either browser as of Feb 2017. The good news is you can rely on window.performance.navigation.type == 2 for chrome and IE. Ironically Firefox is unreliable for the latter but it shouldn't matter since it is reliable for event.persisted. The following code worked for me:
if (document.addEventListener) {
window.addEventListener('pageshow', function (event) {
if (event.persisted || window.performance &&
window.performance.navigation.type == 2)
{
location.reload();
}
},
false);
}
Update 2022:
Because window.performance.navigation.type is deprecated (ref: MDN), I updated the code to do the same thing:
if (document.addEventListener) {
window.addEventListener('pageshow', function (event) {
if (event.persisted || performance.getEntriesByType("navigation")[0].type === 'back_forward') {
location.reload();
}
},
false);
}
This appears to be a bug in Chrome (also present in IE11).
I have found the following workaround:
<input type="hidden" id="cacheTest"></input>
<script>
var input = document.querySelector('#cacheTest')
if (input.value === "") {
// the page has been loaded from the server,
// equivalent of persisted == false
}
else {
// the page has been loaded from the cache,
// equivalent of persisted == true
}
// change the input value so that we can detect
// if the page is reloaded from cache later
input.value = "some value"
</script>
This exploits the fact that in most browsers, when the page is loaded from the cache, form fields values are also conserved.
I know this is a bit late but this works for me:
window.onpageshow = function(e) {
if (e.persisted) {
alert("Page shown");
window.location.reload();
}
};
I don't think you need it in the document ready function, just use vanilla as above.
Got an issue with safari loading old youtube videos when back button is clicked. I have tried adding onunload="" (mentioned here Preventing cache on back-button in Safari 5) to the body tag but it doesn't work in this case.
Is there any way to prevent safari loading from cache on a certain page?
Your problem is caused by back-forward cache. It is supposed to save complete state of page when user navigates away. When user navigates back with back button page can be loaded from cache very quickly. This is different from normal cache which only caches HTML code.
When page is loaded for bfcache onload event wont be triggered. Instead you can check the persisted property of the onpageshow event. It is set to false on initial page load. When page is loaded from bfcache it is set to true.
Kludgish solution is to force a reload when page is loaded from bfcache.
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
If you are using jQuery then do:
$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
window.location.reload()
}
});
All of those answer are a bit of the hack. In modern browsers (safari) only on onpageshow solution work,
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
but on slow devices sometimes you will see for a split second previous cached view before it will be reloaded. Proper way to deal with this problem is to set properly Cache-Control on the server response to one bellow
'Cache-Control', 'no-cache, max-age=0, must-revalidate, no-store'
Yes the Safari browser does not handle back/foreward button cache the same like Firefox and Chrome does. Specially iframes like vimeo or youtube videos are cached hardly although there is a new iframe.src.
I found three ways to handle this. Choose the best for your case.
Solutions tested on Firefox 53 and Safari 10.1
1. Detect if user is using the back/foreward button, then reload whole page or reload only the cached iframes by replacing the src
if (!!window.performance && window.performance.navigation.type === 2) {
// value 2 means "The page was accessed by navigating into the history"
console.log('Reloading');
//window.location.reload(); // reload whole page
$('iframe').attr('src', function (i, val) { return val; }); // reload only iframes
}
2. reload whole page if page is cached
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
3. remove the page from history so users can't visit the page again by back/forward buttons
$(function () {
//replace() does not keep the originating page in the session history,
document.location.replace("/Exercises#nocache"); // clear the last entry in the history and redirect to new url
});
You can use an anchor, and watch the value of the document's location href;
Start off with http://acme.co/, append something to the location, like '#b';
So, now your URL is http://acme.co/#b, when a person hits the back button, it goes back to http://acme.co, and the interval check function sees the lack of the hash tag we set, clears the interval, and loads the referring URL with a time-stamp appended to it.
There are some side-effects, but I'll leave you to figure those out ;)
<script>
document.location.hash = "#b";
var referrer = document.referrer;
// setup an interval to watch for the removal of the hash tag
var hashcheck = setInterval(function(){
if(document.location.hash!="#b") {
// clear the interval
clearInterval(hashCheck);
var ticks = new Date().getTime();
// load the referring page with a timestamp at the end to avoid caching
document.location.href.replace(referrer+'?'+ticks);
}
},100);
</script>
This is untested but it should work with minimal tweaking.
The behavior is related to Safari's Back/Forward cache. You can learn about it on the relevant Apple documentation: http://web.archive.org/web/20070612072521/http://developer.apple.com/internet/safari/faq.html#anchor5
Apple's own fix suggestion is to add an empty iframe on your page:
<iframe style="height:0px;width:0px;visibility:hidden" src="about:blank">
this frame prevents back forward cache
</iframe>
(The previous accepted answer seems valid too, just wanted to chip in documentation and another potential fix)
I had the same issue with using 3 different anchor links to the next page. When coming back from the next page and choosing a different anchor the link did not change.
so I had
House 1
View House 2
View House 3
Changed to
House 1
View House 2
View House 3
Also used for safety:
// Javascript
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
// JQuery
$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
window.location.reload()
}
});
None of the solutions found online to unload, reload and reload(true) singularily didn't work. Hope this helps someone with the same situation.
First of all insert field in your code:
<input id="reloadValue" type="hidden" name="reloadValue" value="" />
then run jQuery:
jQuery(document).ready(function()
{
var d = new Date();
d = d.getTime();
if (jQuery('#reloadValue').val().length == 0)
{
jQuery('#reloadValue').val(d);
jQuery('body').show();
}
else
{
jQuery('#reloadValue').val('');
location.reload();
}
});
There are many ways to disable the bfcache. The easiest one is to set an 'unload' handler. I think it was a huge mistake to make 'unload' and 'beforeunload' handlers disable the bfcache, but that's what they did (if you want to have one of those handlers and still make the bfcache work, you can remove the beforeunload handler inside the beforeunload handler).
window.addEventListener('unload', function() {})
Read more here:
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Using_Firefox_1.5_caching
I've been working on a Frame busting buster (what's in a name, hehe), which kept my users on my page and open a new window with the target URL. I'm using a Lightbox script to display iframes, this is what I'm doing:
1) Added an event for all .lightbox clicks, f.e:
$('.lightbox').live("click", function(e) {
e.preventDefault();
$('#redirectURL').val($(this).attr('href'));
$(this).lightbox();
}
2) Added a frame busting buster:
<script type="text/javascript">
var prevent_bust = 0
window.onbeforeunload = function() { prevent_bust++ }
setInterval(function() {
if (prevent_bust > 0) {
prevent_bust -= 2
window.top.location = 'http://server-which-responds-with-204.com'
}
}, 1)
</script>
3) Modified the frame busting buster code to fit my needs, which are:
detect if an iframe wants to change the window.top.location
if so, prevent this from happening using the 204 server respond
open a new page: window.open( $('#redirectURL', '_blank' );
close lightbox: $('.jquery-lightbox-button-close').click();
So far, this is what I've come up with:
var prevent_bust = 0
window.onbeforeunload = function() { prevent_bust++ }
setInterval(function() {
if (prevent_bust > 0) {
prevent_bust -= 2;
redirectURL = $('#redirectURL').val();
if(redirectURL != "") {
window.top.location = 'http://www.****.com/ajax/nocontent.php';
window.open(redirectURL, "_blank");
$('.jquery-lightbox-button-close').click();
$('#redirectURL').val('');
} else {
window.top.location = 'http://www.****.com/ajax/nocontent.php';
}
}
}, 1);
// EDIT: Before I forget, 'nocontent.php' is a file that returns a 204 header
For Firefox it acts as I programmed it, if there's a change detected in the window.top.location it opens a new frame/page and prevents the iframe from reloading the top location and to round it up, it closes the jQuery lightbox.
Safari/Chrome act similar, they open a new browser screen (not sure if theres an option to say target="_newtab" or something?). Only bad thing is they do not really display a message of the popup is blocked, but I can work around that by displaying a popup balloon on my website with a link to the page.
Internet Explorer is, what a shocker, the only black sheep left.. IE does not open a new popup, nor blocks the window.top.location reset by the iFrame and simply continues refreshing the complete page to the '#targetURL'. It does the same with the default busting code.. so it's not because of some of my edits.
Anyone who is able to spot a mistake in my code?
Also, I would need a little modification that sees if the request has been made by an iframe or by the user itself, because now there is really NO option for a user to leave my page by changing the address in the toolbar or by clicking a link, which is not really needed LOL.
Thanks in advance.
PENDO, I tried to simulate the whole process you described, ligthbox-jquery, javascript their own codes and controls opening pages via lightbox. I could not simulate at all, and as time is running out I'm sending a suggestion to broaden the range of possibilities and solutions.
I suggest replacing the redirect page:
...
redirectUrl = $ ('# redirectUrl'). val ();
...
window.top.location = 'http://www .****. with / ajax / nocontent.php';
window.open (redirectUrl, "_blank");
Replaced with a DIV container that simulates a page, using ajax calls and taking the content and overwritten the contents of the DIV.
...
$.post(redirectoURL /* or desired URL */, function(data) {
$('DIV.simulateContent').html(data);
});
...
or
...
$('DIV.simulateContent').load(redirectoURL);
...
This approach also avoids the problem of preventing the user from even leaving your page using the address bar (as you yourself mentioned).
Sorry, let me give you a complete solution, but time prevented me.
PENDO, a little more work on alternatives to the problem, I found a customizable jQuery lightbox plugin for working with custom windows yet (iframe, html, inline ajax etc.). Maybe it will help. The following link:
http://jacklmoore.com/colorbox/
If you don't need javascript running in your iframe in IE, you can set the iframe security attribute :
<iframe security="restricted" src="http://domain.com" />
http://msdn.microsoft.com/en-us/library/ms534622(v=VS.85).aspx