I want an event handler that fires when the user hits reload. Is onrefresh or onreload the correct handler to add to ? Also, will this even fire before or after onunload? Are there an browser inconsistencies? Thanks.
I don't think there are events called onrefresh or onreload. You can know when the page is unloading, but knowing why (i.e. where the user is going next) is outside JavaScript's security sandbox. The only way to know whether the page has been reloaded is to know where the user was on the last page request, which is also outside the scope of JavaScript. You can sometimes get that via document.referrer, but it relies on the browser's security settings to permit access to that information.
The WindowEventHandlers.onbeforeunload event handler property contains the code executed when the beforeunload is sent. This event fires when a window is about to unload its resources.
window.onbeforeunload = function () {
return 'Are you sure you want to leave?';
}
This will show a confirm dialog to the user with the message you returned in your function. It will give the user a leave this page or cancel option.
There is no way around the confirm as it could be used for malicious reasons.
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload
If you combine setting a cookie with a for the specific page, with a check for the onload event, you can simulate the nonexistent event you seek. You might adjust the cookie expiration so that a reload is counted only if the initial onload was a certain time interval ago.
There are no onreload or onrefresh events that I'm aware of. Certainly from javascript running in a browser this make little sense. The existing window and all its contents are effectively discarded. Hence you either need to use onunload of the existing context or the load event of the new context that is created as result of reload.
I do believe artlung may have indeed found a way, actually... his version, however, relies on cookies, and those can be cut off from use in numerous ways; the solution, then, is to use a server-side language of your choice to save the timestamp of when the page is unloaded via JavaScript (still a vulnerability, yes, but why not throw another idea out there, huh?) and then testing it again upon every page load; if you detect a difference of less than a few seconds, the user probably just reloaded your page. : )
could use a session. easier than a cookie and don't have to worry about expiration or database. That would cover you for any page except the first one. I don't think the session superglobal is available til the second page. If that's a problem, you could start a session and reload the page immediately if there is no active session.
its onunload
because when you hit refresh the browser "unloads" then loads again
Related
I've set up a fiddle to try to verify if the beforeunload event is triggered when the page is used in an iframe.
Since the fiddle show its result in an iframe, I figured it could be easy to verify by just closing the page. I've set up a request bin at pipedream just to see if any requests gets sent, but it doesn't seem to trigger in Chrome.
window.onbeforeunload = function() {
fetch('https://eoaczcjrpegb7wv.m.pipedream.net')
}
Is is possible to use this event from an iframe or do I need to look in to a different approach?
After a closer look it seem to capture some of the requests. Is this prone to race conditions? If so, are there any more robust alternatives?
Yes, there is a race condition. Since your event handler does nothing to stop the page unload in any way (it does not even trigger a confirmation prompt to delay it), immediately after your event handler is processed, the browser will proceed to unload the page. This aborts most pending requests; if a request did not manage to be submitted at that point, it will not be sent to the server at all.
Sending a request from a beforeunload event handler is a poor idea anyway. For starters, you are not even guaranteed that the event will fire at all; the browser may be unable or unwilling to trigger the event. MDN warns that it will only fire after the user had interacted with the page and it may fail when the session is terminated out of browser’s control. The only legitimate purpose of beforeunload is to check whether the page contains any unsaved state that the user may lose, and to trigger a confirmation prompt; even that should be understood to work on a best-effort basis. Anything else is prone to abuse and suspect; I would not be surprised if a future browser plug-in or vendor ‘intervention’ were to block all web requests when a page is about to unload.
However, if you insist, there are ways to make the request survive unload. You can use navigator.sendBeacon:
window.onbeforeunload = function () {
navigator.sendBeacon('https://example.net', '');
};
or the keepalive fetching option:
window.onbeforeunload = function () {
fetch('https://example.net', { keepalive: true });
};
Chrome provides both, but Firefox, as of version 106, only implements the former. Using those APIs comes with some restrictions: at any given moment, the total amount of data sent by active keep-alive requests must fit within 64 KiB, as per the Fetch specification.
You may notice using those APIs in a beforeunload handler is still not recommended usage, as it worsens performance of navigating back to the page with the back button. MDN suggests listening for the visibilitychange event, but that is of course not the same thing.
Last but not least, nothing stops the user from having the browser lie to you that the request has been sent, like with this uBlock filter:
##+js(no-fetch-if, keepalive:true)
##+js(set, navigator.sendBeacon, trueFunc)
So try not to be too obnoxious with your spyware ‘analytics’.
I am making an extension that needs to capture POST data directed to a site and once the site response confirms success, change some local data to reflect it.
The issue is, the POST data is located in requestBody from the onBeforeRequest event, while the success confirmation is in the onCompleted event. I understand that the lifetime of a webRequest should be managed using its unique requestId, but I am using an Event Page and therefore trying to avoid the use of global variables.
eventPage.js:
function continueListening(requestDetails){
function finishListening(completeDetails){
if (completeDetails.requestId === requestDetails.requestId){
doStuff(requestDetails, completeDetails);
chrome.webRequest.onErrorOccurred.removeListener(finishListening);
chrome.webRequest.onCompleted.removeListener(finishListening);
}
}
chrome.webRequest.onErrorOccurred.addListener(finishListening,{urls:["*://site*"]});
chrome.webRequest.onCompleted.addListener(finishListening, {urls:["*://site*"]});
}
chrome.webRequest.onBeforeRequest.addListener(continueListening, {urls:["*://site*"]});
I decided to try nesting listener registrations for the finalized request in order to provide them with the scope to compare requestIds with the initial request containing the form data. This appears to work, but I am concerned about a potential race condition between the resolving of the webRequest and the registration of the nested listener intended to listen for it, leading to any number of useless unremoved listeners.
The other option I see is to store the requestDetails in chrome.storage.local and check them against the completeDetails once they arrive. My main hesitation there is that if for whatever reason execution is interrupted the local disk space could be polluted with unresolved requests.
Is there a better way of doing this?
EDIT: Unfortunately although I believed I was making an Event Page, I did not have persistent:false in my manifest. As I learned when I added it, Event Pages do not even support webRequests. The Event Page equivalent, declarativeWebRequest, seems to have died in the beta channel. So making it a Background Page seems to be the necessary solution.
I am building SPA application is emberjs framework and I need to ensure that the application instance is running only once (on single tab) on same domain.
Analogy of mutex to prevent multiple instances known from desktop application development world.
There are some solution I am considering just now like using localStorage locks or window.postMessage or SharedWorker but non of them looks bulletproof to me.
Do you have some ideas?
Thanks is advance.
I've used localStorage to make sure when users log out in one tab it logs them out in other tabs and it's worked quite well.
Bind to the storage event on the window object and use the event.key/event.newValue keys to determine what action to take. You can also use the event.url key to make sure the storage event is firing from the correct page. In my code I set a logged-out flag if the url, key and newValue data validates.
Bind to the focus event on the window object and check the value of the logged-out flag and auto-logout the user if it's set to true.
For my purpose I had to initialize the localStorage data to "not logged out" on page load because the storage event will not fire if you don't actually change the value of the localStorage key you're watching. I.e. if the value is blah and you set it to blah, no event will fire.
This works back to IE 8 too.
For your purpose you could set a localStorage key/value when someone logs in and block the page from working if that key/value is already set. Maybe set a timestamp as the value so if someone doesn't properly logout they can get back in after so many seconds. Then set an interval to update the timestamp while the user is logged in.
This is untested, if you go down this road I'd be interested to see how it works for you and what you had to do to make it work.
I am trying to post data when user arrives my page. This works in chrome and explorer, and also firefox, but however, on firefox, it strangely only works if user closes the page. If they go back, or goes another site (by typing to address bar or whaever) it doesnt post the data. My question is, what is the correct way to use onbeforeunload to post data ?
$(window).bind('beforeunload', function () {
$.post("track.php", {
async: false,
ip: ip,
referer: referer,
clicks: kactane2,
scrolls: kactane,
time: time,
refid: refid,
country: country,
});
});
There isn't a good way because that is not how onbeforeunload was meant to be used.
The correct way to use onbeforeunload is to listen for this event and then unload any data or resources you might be using because the user is leaving the page. You should not use it to try to start new things. According to the HTML5 specification showModalDialog(), alert(), confirm() and prompt() are explicitly not allowed and the idea is to give you a moment to clean up any event handlers, web workers and other stuff cleanly.
If an event handler is defined then the user may be presented with a page that says "Are you sure you want to leave?" but for security reasons the form is generally not able to be customized, but it depends on the browser.
You will probably be better off setting the data in a cookie or something that can be done quickly and that is only occurring in the browser, then just look for that data on the next page load.
In Chrome, I'm looking to detect in a page URL is going to be on example.com's domain, and if it is, before loading, append foo=bar as a parameter and load that instead.
I've found that I can access when the Omnibar has been submitted here, but it seems like it'd load the original URL anyways, and while that's alright it's twice the bandwidth I feel is necessary. It's not a problem when it's only one page, but it's a change that needs to happen on every page in an site, so double the bandwidth definitely becomes an issue.
Currently, it works to detect if the URL is going to be example.com and is submitted, then call window.stop() and then set location.href to example.com/&?foo=bar but that doesn't seem ideal.
In short, the user goes to http://www.example.com and then the script changes it to http://www.example.com/&?foo=bar before loading the original link.
Take a look at the chrome.webRequest API, in particular the following method:
onBeforeRequest (optionally synchronous)
Fires when a request is about to occur. This event is sent before any TCP connection is made and can be used to cancel or redirect requests.
You can use
window.location.search = "foo=bar"
may be this helps.