I'm using the beforeunload event to as a means to proxy into metrics about clicks on my site. For example, if beforeunload fires within ~50ms of a click event, I can determine when a user has selected a link.
This gets complicated with iOS, as it doesn't support beforeunload. As per Apple docs, I've substituted pagehide for beforeunload, but this doesn't have the same functionality. It looks as if pagehide replaces unload - NOT beforeunload. In my tests their time to fire differs by ~1500ms on average (pagehide triggers much later than beforeunload). This makes attributing pagehide events to clicks very difficult.
Is there any event supported by safari on iOS that can get close to the trigger time of beforeunload?
NOTE: I know this isn't ideal, and there are other, better approaches which I will likely end up pursuing, but I was still curious about this.
Theoretically pagehide is replacement for beforeunload in safari but practically its not. As correctly observed time to trigger pagehide event can vary because safari fetches the new page in the background and when page is available it fires pagehide.
There is no event if you are looking for one but there is this hack which you can try, as soon as click happens safari stop running requestAnimationFrame. So you can try something like this, as click happens record clickTs and start recording timestamp inside requestAnimationFrame function, now when pageHide fires you just check the time difference between clickTsand eventlastReqAnimTime, it should be roughly between 500 ms. This way you can attribute click to pageHide
var w = window,
reqAnim = null,
clickTs = 'record this when click happens',
eventlastReqAnimTime = +new Date,
logReqAnim = function() {
eventlastReqAnimTime = +new Date;
reqAnim = w.requestAnimationFrame(logReqAnim)
};
reqAnim = w.requestAnimationFrame(logReqAnim);
setTimeout(function () {
w.cancelAnimationFrame(reqAnim);
}, 1500)
w.addEventListener('pagehide', function(){
if(Math.abs(clickTs - eventlastReqAnimTime) < 500 ){
console.log('your link was chosen')
}
})
NOTE: above code is just pseudo, test before running.
Related
I have the following jQuery code in my page onload function:
$("#vid-pages").find("video").on('canplay', function() {
$(this)[0].currentTime = $(this)[0].duration / 2;
console.log($(this)[0].currentTime);
});
There are only two videos in that container, and none anywhere else on the page. When I check the console, it's continuously flooded with the time returned in that code block. What is the solution to make this trigger only once, instead of constantly?
When the current time is changed the browser needs to load more data either from cache or the network. This can trigger the canplay event. And since a time is set in the event handler you will get a never-ending loop (you can see the effect of canplay being triggered here by choosing a video, hit play then skip to the middle right after). It may depend on the browser.
This page on MDN states the following to the related canplaythrough (though not entirely the same it is reasonable to believe this also applies to canplay as shown in the media event page using Firefox):
Note: Manually setting the currentTime will eventually fire a
canplaythrough event in firefox. Other browsers might not fire this
event.
To avoid either unsubscribe from the event, or use a flag which forces exit at the second time the event is triggered.
var initialPlay = false;
$("#vid-pages").find("video").on('canplay', function() {
if (initialPlay) return;
initialPlay = true;
$(this)[0].currentTime = $(this)[0].duration / 2;
console.log($(this)[0].currentTime);
});
For unsubscribing you would need to use a non-anonymous function.
If an element is clicked twice, the 'dblclick' event is fired. If the element continues to be clicked, the 'dblclick' event does not continue to be fired. The 'dblclick' event will only be fired once until a "cooloff" period is complete, eg. there is a time to wait before another 'dblclick' event can be fired no matter how many times the element is clicked.
I cannot find any documentation that specifies how long must elapse before another 'dblclick' can occur. Does anyone know what the 'dblclick' "cooloff" period is?
I have tried to test this by scripting the clicking of an element, but for some reason javascript-invoked clicks do not trigger 'dblclick' events. So I have tested manually and I can't get a double-click to occurred any sooner than ~400ms after another double-click has occurred. You can try yourself: https://jsfiddle.net/5v4pcx2k/8/
code
If you're wondering, this is basically what it seems like the browser is doing https://jsfiddle.net/b0y5ej2y/3/
There are quite a few bugs and inefficiencies in your jsfiddle.
h1 element has no end tag (you think your ending it with /hi)
you don't need jquery
the general advice around the webs, seem to be don't mix click and dblclick event listeners on the same element
the event already has a property on it that tells you when it fired, you don't need to ask for the current time again with Date.now()
Having said all that, I still couldn't manually click any faster than about ~700ms. I think what's happening is it's the window manager / OS / mouse driver is artificially holding back double clicks to some speed limit.
Here's my version of a jsfiddle test for dblclick speed, with a working programatic dblclick simulation which can dblclick as fast as every 4ms on my computer.
https://jsfiddle.net/stephencarmody/v0b3dpwc/
var lastOne;
foobar.addEventListener('dblclick', function (event) {
log.innerText = 'elapsed: ' + (event.timeStamp - lastOne);
lastOne = event.timeStamp;
});
function simulateClick () {
var event = new MouseEvent('dblclick', {
'view': window,
'bubbles': true,
'cancelable': true
});
foobar.dispatchEvent(event);
}
setInterval(simulateClick, 0);
Comment out the setInterval line to test manual dblclick events.
i have that problem: i need to have a variable set to false/true depending on whether the page is loaded in the current tab or in an inactive tab. so i tried to do it with the focus-event, more or less like this (it's jquery):
var hasFocus = false;
$(function() {
$(window).focus(function() {
hasFocus = true;
});
});
firefox and ie it do what i want: if the page is loaded in the active tab the event is triggered immediately, loaded in a background tab the event is only triggered when the tab gets active.
in chrome however the event does not get triggered when the page is loaded in the current active tab. does anybody know a workaround for this? i also tried events like mouseenter, hover but unfortunately they get executed on pageload in an inactive tab too... thanks in advance!
A tricky way would be this.
setInterval/setTimeout is only fired once a second at most for inactive tabs in Chrome. So, you could set an interval (or timeout) to be run after e.g. 10ms. If it only runs after a much longer time (e.g. 1 second), the page must be inactive. Otherwise, it would be run in 10ms (like you set).
I woulds suggest that you try mousemove as an event -- e.g.
var humanHasInteracted = false;
$(function() {
$(window).mousemove(function() {
humanHasInteracted = true;
});
});
alternatively use bind/unbind so that the event handler can removed when the first mousemovement is detected.
I develop an app using phonegap and jquerymobile/jquery.
During development I only had a virtual iOS device and now since I'm testing the app on a real device I see, that time between click on an element and handle this event is very long.
E.g if i Click on an icon a loader icon is shown but this icon first come in the moment the next page is final loaded (a very short time the loader is shown).
I develop with Javascript since a long time and always have focus on performant execution but this is very strange.
The App has got about 10 views in one HTML file. And on click on an element only show the next part of these file.
Does anyone know about solutions to solve "Bugs" like these?
Thanks in advance.
The click delay on iPhones is a feature used to distinguish between clicks and scrolls. When you bind to the click event iOS waits approximately 300ms to decide whether you were clicking an object or trying to scroll the page.
You can use jQuery Mobile's vclick event which fires much faster however you will probably run into situations where the vclick event is fired off twice in a row which can result in multiple elements being clicked. Here is some sample code of how to use vclick events and only capture the event triggered first:
$(function () {
//setup a function to check if a vclick event has fired within the last 500ms
function check_vclick () {
//if a vclick event has fired in the last 500ms then return false
if (do_vclick == false) return false;
//otherwise set a flag to disallow vclicks for 500ms
do_vclick = false;
//setup a timeout to allow vclicks in 500ms
setTimeout(function () {
do_vclick = true;
}, 500);
//return true so the event handler knows it's ok to run its code
return true;
}
//setup a flag to allow/disallow vclick events from firing
var do_vclick = true;
//bind an event handler to the vclick event for an element
$('#link_id').bind('vclick', function () {
if (check_vclick()) {
//run the code associated with the element, if it's a link referencing a pseudo-page on the same HTML document, you can do something like this
$.mobile.changePage($(this.href));
}
});
});
Here's a link to the documentation for $.mobile.changePage(): http://jquerymobile.com/demos/1.0rc2/docs/api/methods.html
Here's a link to the documentation for vclick (notice the notes under the virtual mouse event section): http://jquerymobile.com/demos/1.0rc2/docs/api/events.html
Is it possible to determine whether a user is active on the current web page or, say, focused on a different tab or window?
It seems that if you switch tabs, any JavaScript set on a timeout/interval continues running. It would be nice to be able to 'pause' the events when the user is not on the page.
Would something like attaching a mouseover event to the body work, or would that be too resource-intensive?
You can place onfocus/onblur events on the window.
There's wide support for those events on the window.
Example: http://jsfiddle.net/xaTt4/
window.onfocus = function() {
// do something when this window object gets focus.
};
window.onblur = function() {
// do something when this window object loses focus.
};
Open Web Analytics (and perhaps some other tracking tools) has action tracking
You could keep an alive variable going using mousemove events (assuming the user does not leave the mouse still on the page). When this variable (a timestamp likely) has not been updated in x seconds, you could say the page is not active and pause any script.
As long as you do not do a lot of processing in the body event handler you should be okay. It should just update the variable, and then have a script poll it at a certain interval to do the processing/checks (say every 1000ms).
Attach listeners to mousemove, keyup and scroll to the document.
I use this throttle/debounce function (which works without jQuery, even though it's a jQuery plugin if jQuery is present) to only run code in response to them once in ~250ms, so that you're not firing some code on every pixel of the mouse moving.
You can also use the visibilityState of the document:
document.addEventListener("visibilitychange", function() {
if( document.visibilityState === 'visible' ) {
// Do your thing
}
});
There is a wide acceptance of this API.