Delaying window.open inside click event handler - javascript

For some days now I've been trying (without success) to open new window with delay without Chrome blocking it most of the time. Delay is crucial for my task, because some animation must take place before window is opened and I can not afford browsers to block new tabs from opening. Here is sample from my code:
element.on("click", function(e){
e.preventDefault();
var self = $(this),
url = self[0].href;
window.setTimeout(function(){
window.open(url);
}, 1000);
});
element is jQuery object (anchor element to be more precise). I have noticed that I have bigger success rate if I pass string directly like this
window.open("http://example.com");
I've tried this solution in Explorer(no problem), Chrome(problem), Firefox(no problem) and Opera(problem). I am loosing my mind, because I've tried everything I can remember. Synchronous ajax calls, artificially triggering click, creating fake anchor elements and artificially triggering click event. Nothing works fine.
Bonus question (in case someone knows how to solve problem): is there a way to call window.open anytime & anywhere from code?

This is working for me in Chrome http://jsbin.com/wuqopukayuwi/4/
var $element = $('#link');
$element.on('click', function () {
var url= $(this).attr('href');
window.setTimeout(function(){
var windowObjRef = window.open(url);
console.log(windowObjRef);
}, 2000);
});
Things to check:
Obviously, double check you've enabled popups for your domain in Chrome (it prompts you the first time it tries to pop up a new window
It's because Chrome expects to be able to access that window again programatically, so wants you to declare the response to the method as a variable. At least, that's how I got it working...

As long as you know how long the animation runs then you sleep for number of seconds
Add sleep(), msleep() and usleep() to Node.js, via a C++ binding.
This is mainly useful for debugging.
These calls will block execution of all JavaScript by halting Node.js' event loop!
Usage
`var sleep = require('sleep');
sleep.sleep(n): sleep for n seconds
sleep.msleep(n): sleep for n miliseconds
sleep.usleep(n): sleep for n microseconds (1 second is 1000000
microseconds)`

Related

Why doesn't window.open get blocked on a setTimeout <= 1000ms?

document.querySelector('#ontime').onclick = function() {
setTimeout(() => {
window.open('https://www.google.com');
}, 1000);
};
When using window.open after a user click with a timeout <= 1000ms (or a Promise.resolve().then(...)) it doesn't get blocked by the browser.
If you do the same using a timeout > 1000ms or requestAnimationFrame, the popup gets blocked.
Full example with the 4 cases is available clicking the link below:
https://jsfiddle.net/kouty79/rcwgbfxy/
Does anybody know why? Is there any documentation or w3c spec about this?
From HTML 5.2:
An algorithm is allowed to show a popup if any of the following conditions is true:
…
event listener for a trusted event
…
… queued by an algorithm that was allowed to show a popup, and the chain of such algorithms started within a user-agent defined timeframe.
onclick is a trusted event, but setTimeout put it in a queue (so it wasn't called directly) so the popup has to come within a certain time.
That time is up to the browser to decide.

Javascript event for mobile browser re-launch or device wake

Morning all, I'm looking for some kind of Javascript event I can use to detect when a mobile browser window regains focus, after either a user closes/minimizes their browser (to go back to a home screen/different app), or if the device resumes from sleep (either the user powering it off, or it going to sleep after a screen timeout).
I'd like to be able to find a single event that works for everything, but I know that's unlikely! The pageshow event works for iOS devices, but it's rather sketchy for use with everything else. I've tried focus and DOMActivate but neither of them seem to have the desired effect.
The page may not always have form elements on it, and I don't really want the user to have to touch the page again to trigger the event.
The requirement for such an event is caused by our code periodically checking for new content by making XHR requests. These are never sent when the browser is asleep, so we never get new content to restart the timeouts.
Thanks for any help you guys may be able to provide!
We had a similar issue and solved it something like this:
var lastSync = 0;
var syncInterval = 60000; //sync every minute
function syncPage() {
lastSync = new Date().getTime(); //set last sync to be now
updatePage(); //do your stuff
}
setInterval(function() {
var now = new Date().getTime();
if ((now - lastSync) > syncInterval ) {
syncPage();
}
}, 5000); //check every 5 seconds whether a minute has passed since last sync
This way you would sync every minute if your page is active, and if you put your browser in idle mode for over a minute, at most 5 seconds will pass before you sync upon opening the browser again. Short intervals might drain the battery more than you would like, so keep that in mind when adapting the timings to you needs.
Better than an interval would be to add a window blur listener and a window focus listener. On blur, record current time. On focus, validate you are still logged in / sync'd / whatever you need to do.
Basically exactly the same thing but it runs only when necessary rather than slowing your entire page down with an interval.
Update
var $window = $(window),
$window.__INACTIVITY_THRESHOLD = 60000;
$window.add(document.body); //necessary for mobile browsers
$window.declareActivity = function () { $window.__lastEvent = new Date(); };
$window.blur($window.declareActivity);
$window.focus(function(){
var diff = (new Date()) - $window.__lastEvent;
if (diff > $window.__INACTIVITY_THRESHOLD) {
$window.trigger("inactivity");
}
});
$window.on("inactivity", "", null, function () {
//your inactivity code
});
Though that blur event seems sketchy if the phone is powering off and I don't know that I would trust it in all circumstances / mobile devices. So I'd probably throw in something like this:
$(document.body).on("click scroll keyup", "", null, $window.declareActivity);
so that my inactivity timer works for when the user just walks away as well. Depending on your site, you may want to adjust that exact event list - or simply throw in a $window.declareActivity(); into your existing scripts that respond to user inputs.

How PhoneGap keep Javascript executing after changing window.location/document.location

According to this question, when we set the window.location, javascript will "stop" executing or turn into a race condition.
Sometimes we need to fire window.location = SOMESCH://xxx multiple times inside a WebView to send "Notifications" back to our app. For example setting window.location = myapp://loginButtonEnabled?e=1 to tell the app that the user had filled in some nessasary info and can start login. It seems to be impossible to do something like this:
function(){
window.location = myapp://loginButtonEnable?e=1;
window.location = myapp://hideHintView;
.....
window.location = myapp://theLastThing;
}
Only the last window.location = myapp://theLastThing will be fired and then the execution of Javascript will stop(though we stopped the redirecting in our app by returning NO in webView:shouldStartLoadWithRequest:navigationType:).
I found it interesting that PhoneGap made this possible by using a dispatching queue, but I still haven't figure out why it works, anybody knows the trick??
BTW, is there a simple way to "resume" the execution after setting location? It will be much better than using an operation queue.
You need to give the event loop a chance to respond to the location change each time. The typical way of doing this is using a setTimeout with a small/zero delay, which has the effect of moving execution to the next event loop tick. Try something like this:
var q=[];
function dequeue() {
window.location='myapp://'+q.shift();
if (q.length>0) setTimeout(dequeue,0);
}
function notifyApp(cmd) {
q.push(cmd);
if (q.length==1) setTimeout(dequeue,0);
}
notifyApp('loginButtonEnable?e=1');
notifyApp('hideHintView');
notifyApp('theLastThing');
As for javascript execution stopping, setting window.location shouldn't have this effect unless it actually results in a page change - perhaps try using the technique above and see if your javascript continues after the last notifyApp() call.
EDIT: Another approach to this issue is to create temporary iframes instead of changing the location of the current page - see for example
Triggering shouldStartLoadWithRequest with multiple window.location.href calls

Chrome JavaScript location object

I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.

Annoying Popup - (or other more graceful solution)

Here's my "need" - I have a user opening a window with a document displayed, I need to log the amount of time the user has that window "in focus" or "opened"... IF the user views another window, I want to stop logging the time - and resume logging if they re-focus on that page... basically I want to "know" how long it took a user to read the page.
this is a review type scenario, where the users is a 'trusted' member who needs to log their time... I want to keep a 'running total' for reference only - so if the user says that spent 10 min, on the page, but my log shows the window was only open for 2min, I know I've got a problem...either with my code or my people.. ;)
My thought was to keep a js counter going when the page was in focus, pause on blur or on close, and Ajax the data back to my db... and add any subsequent time to that record if the user returns...
onUnload doesn't seem to work, at least when i try - plus it doesn't catch a closing of the browser... so I was thinking I could launch a NEW window, when the document window is closed (not to be annoying - but to make the logging call to the server, and then close itself).
Does anyone have a solution for this? I know this all smacks of 'poor' design, but if someone has a 'correct' way to handle this scenario - please tell me. (BTW- IE is a requirement- it's intranet based IE7 req.)
Thx
======== sample code below - that is 'not' working...kinda ============
When i say it's NOT working, this is what I mean... The "XMLHttpRequest" Is being made, i assume because the response is the message I'd expect - HOWEVER the log isn't changes (I know you'll say it's the php page, but if I call the url directly - it works fine... so it's no the logging page, IN ADDITION the 60 second setInterval() seems to fire randomly, because my response alert just pops up, sometime 10 in a row with no time between, certainly not at 'regular' 60 sec intervals... THOUGHTS?
<script type="text/javascript">
var closeMe = 0;
var logMe = 0;
//the window doesn't have focus, do nothing or something that let's them know we're not logging at the moment
function onBlur() {
//after 2 min of non focus, close it.
closeMe = setInterval('window.close()',120000); //after 2 min of non focus, close it.
};
//the window has focus... keep logging.
function onFocus(){
//stop the close counter - in the event to 'blurred' sometime
clearInterval ( closeMe );
//run the AJAX on a schedule - we're doing it every minute - bu tyou can do it as often as you like
logMe = setInterval('logTime()',60000);
};
//call a script that logs another minute...
function logTime() {
var xhReq = new XMLHttpRequest();
xhReq.open("GET", "ajax-on-time-interval.php", false);
xhReq.send(null);
var serverResponse = xhReq.responseText;
alert(serverResponse);
}
// check for Internet Explorer... IE uses 'onfocusin/out" - everything else uses "onfocus/blur"
if (/*#cc_on!#*/false) {
document.onfocusin = onFocus;
document.onfocusout = onBlur;
} else {
window.onfocus = onFocus;
window.onblur = onBlur;
}
</script>
I've have thought that a regular Ajax based "heartbeat" that updates the underlying database data every 'n' seconds (depending on the granularity you require, I'd have thought every minute would be sufficient) would be a neater solution than a pop-up and also avoid the fact that not all browsers handle onunload, etc. gracefully.
That said, I'm presuming that JavaScript will be enabled on these machines. (Seems fair based on your question.)
window.onfocus and onblur are documented in the MDC, but they're not standards. Evidently IE has document.onfocusin and .onfocusout :
if (/*#cc_on!#*/false) { // check for Internet Explorer
document.onfocusin = onFocus;
document.onfocusout = onBlur;
} else {
window.onfocus = onFocus;
window.onblur = onBlur;
}
I haven't tried it. I just read about it here.
http://www.thefutureoftheweb.com/blog/detect-browser-window-focus
One somewhat sloppy solution that partially resolves the issue with the browser closing/crashing is to have an ajax function that pings the server DB at a set interval while the document is in focus. This way, if the client crashes, you will be accurate within 30 seconds of how how long the document was open.

Categories

Resources