set window.location after wait - javascript

I have a callback function that changes
window.location.href = url;
however, this callback is invoked after checking whether an image exists in a different page (and different domain).
My problem is that IE9 won't let me do the following:
$(testImage)
.bind("load readystatechange", function (e) {
if (this.complete || (this.readyState === 'complete' && e.type === 'readystatechange')) {
callbackFunction(true);
}
})
.bind("error abort", function () {
abort();
})
.attr("src", testUrl);
IE9 WILL however allow me to do this:
callbackFunction(true);
but as I want to wait and see that my image exists, I need the above to work. (I don't want to change IE settings) Of course, it all works just fine in Chrome.
Anyone got any ideas?
Edit: I think I should clarify: "when I say ie9 wont let me do.." I mean that ie9 executes the callback BUT the code inside (changing url) don't work.

IE also supports the load event on images, you don't have to explicitly check the .readyState property unless you have another reason you didn't mention.
So it should absolutely be enough to go like
$( testImage ).on('load', function( e ) {
callbackFunction( true );
});

Related

window.onload doesn't work within Android WebView

I'm working on an issue for the 2048 game which is a webapp that's been ported to Android:
https://github.com/uberspot/2048-android/issues/15
The JavaScript seems to work everywhere except for a button that toggles a style change in the app. The JavaScript works in a browser, just not in the app. I think it comes down to some code in nightmode.js which begins:
window.onload = function() {
var a = document.getElementById("night");
a.onclick = function() {<<code that toggles day and night colors>>}
Does anyone have a solution to why this JavaScript isn't getting run?
Edit: When on Desktop Chrome and the screen is resized all the way down, the button continues to work. But switching the device mode in Chrome reveals that the thing never works for mobile devices. Since this behavior happens even without the WebView, it looks like just a javascript problem now.
The onload event is fired when everything is loaded. This can take some time.
Plus, window.onload might get overwritten later on...
You can try this instead:
var ready = function ( fn ) {
// Sanity check
if ( typeof fn !== 'function' ) return;
// If document is already loaded, run method
if ( document.readyState === 'complete' ) {
return fn();
}
// Otherwise, wait until document is loaded
// The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets and frames are still loading. The state indicates that the DOMContentLoaded event has been fired.
document.addEventListener( 'interactive', fn, false );
// Alternative: The document and all sub-resources have finished loading. The state indicates that the load event has been fired.
// document.addEventListener( 'complete', fn, false );
};
// Example
ready(function() {
// Do night-mode stuff...
});
see: http://gomakethings.com/a-native-javascript-equivalent-of-jquerys-ready-method/

mac window load doesn't always fire

My load events do not always fire in safari or chrome on mac (safari version 7.0.5, chrome version 43.0.2357.124). It works fine in firefox and in any of my windows browsers.
window.addEventListener('load', function (){
alert("loaded js");
}, false);
$(window).bind("load", function() {
alert("loaded jquery");
});
Both functions fire or none of them does.
Does someone know what is happening here?
Thanks for help.
Since that JS is in a separate file, I can imagine that at the time it runs, the load event has already been fired.
You can detect this, however, using document.readyState (see also this question).
It has three possible values:
loading - parsing is still going on
interactive - parsing has finished, but resources are loading
complete - pasing has finished and resources have been loaded
I suggest you check whether document.readyState == 'complete' and run your code, otherwise register an event listener:
~function()
{
var loadJS = function()
{
alert("loaded js");
};
var loadJQ = function()
{
alert("loaded jquery");
};
if(document.readyState == 'complete')
{
loadJS();
loadJQ();
}
else
{
window.addEventListener('load', loadJS, false);
$(window).bind('load', loadJQ);
}
}();

Chrome extension, javascript: Why is this firing twice?

I have a very very simple bit of code in my (test) Chrome extension:
function test()
{
alert("In test!");
}
chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
var url = tab.url;
if (url !== undefined) {
test();
}
});
My question is, why is test() firing twice? And more importantly, how do I make it fire just once?
Have a look at what the different states are when the event is dispatched. I presume, that it is getting dispatched once when the state is "loading" or when the state is "complete". If that is the case, then your problem would be fixed with:
function test()
{
alert("In test!");
}
chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
var url = tab.url;
if (url !== undefined && changeinfo.status == "complete") {
test();
}
});
I was also confused by this and tried to find the answer. Only after some experimentation did I figure out why I was receiving multiple "complete" update events for what I thought was a single page "update".
If your page has iframes, each will trigger a "complete" event and bubble up to the parent content script. So more complex pages will trigger a slew of onUpdated events if they have iframes.
When you write the following code:
chrome.tabs.onUpdated.addListener(function(tabid, changeinfo, tab) {
var url = tab.url;
if (url !== undefined) {
test();
}
});
You're calling addListener and telling it to call test() not immediately but rather whenever the tab is updated. Tab update events are broadcast by the Chrome browser itself, which in turn, causes your test() code to run.
I know this is old but anyway... it's happening to me too and maybe this can help someone. Looking into the Tab object that the handler function is receiving, I saw that the favIconUrl property is different in both calls so I guess it has something to do with that although I have no idea about the reason behind this.
I thought it was a bug but after a second thought and some testing I discard the bug theory.
What I know so far is that if two properties are changed, the event is triggered twice with the changeInfo object containing one property each time. In other words if for instance the properties that change are status and favIconUrl, then
changeInfo = {status:"complete"};
and then in the next call
changeInfo = {favIconuUrl : ".... whatever ..."};
Although I'm not sure why our code is firing twice, I had a similar problem and this answer helped me out a lot.
https://stackoverflow.com/a/49307437/15238857
Vaibhav's answer was really smart in incorporating validation in the form of the details object of the request.
When logging the details object I noticed a trend that the original firing had a frameId of 0, and the second firing was always something else. So instead of positively validating that you're in the correct submission of the URL, I like using an if statement to return and bail out when you have the duplicate entry.
I'm using onCompleted here, but it should work for onUpdated as well.
chrome.webNavigation.onCompleted.addListener(details => {
//need to make sure that this only triggers once per navigation
console.log(details);
if (details.frameId !== 0) return;
});
I solved this problem by checking the title of the tab when updated:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
var title = changeInfo.title;
if (title !== undefined) {
doSomething();
}
});
Twice is due to status being loading once and status being completed once.
if you are unconcerned about the status, you may also try the onCreated event. That will be fired just once!

jQuery .load() not firing on images (probably caching?)

I have some pretty basic jQuery code:
...
$(this).find('img').load(function(){
loadedImages++;
if(loadedImages == $this.find('img').length){
...
However, thats not firing consistently. It fires if i do a hard refresh or close my browser, but a normal refresh, or just hitting the same URL twice at any time without erasing the cache makes the .load() never fire.
Any ideas on how to fix this?
I think this has been discussed before. It’s not the caching per se that is the problem but the timing: the images may already have been loaded by the time the event handler is attached (so it never gets fired). This may also occur if no caching happens, for example in a multithreaded browser on a very fast connection. Fortunately, there is a property .complete that you can use:
var load_handler = function() {
loadedImages++;
…
}
$(this).find('img').filter(function() {
return this.complete;
}).each(load_handler).end().load(load_handler);
You can also create your own event attach function:
jQuery.fn.extend({
ensureLoad: function(handler) {
return this.each(function() {
if(this.complete) {
handler.call(this);
} else {
$(this).load(handler);
}
});
}
});
And then call it as follows:
$(this).find('img').ensureLoad(function(){
loadedImages++;
if(loadedImages == $this.find('img').length){
…
});
A way would be to add a "dummy variable" at the end of the URL that you use to grab the image... such as the time in milliseconds appended as a query string param.
Edit: Preventing the Browser to Cache images is a very bad idea in 99% of the cases as it will slow down your application. Instead you should check if an image is already loaded, and if not wait for the load event to complete.
As Ron and El Guapo said, the answer is to add a query at the end of the URL. I did this like this:
$(this).find('img').each(function(){
$(this).attr('src',$(this).attr('src')+'?'+new Date().getTime())
}).load(function(){
//This will always run now!

document.readyState analog for gecko-based browsers

IE has attribute readyState in document object, that indicates current state, e.g. "loading", "complete" etc.
Is there any way to find current loading state of document in Mozilla-based browsers?
I'm aware of DOMContentLoaded event, but it wont fit my situation, as my code can be executed after this event was fired.
Added: no, I can't use any framework, and don't confuse with .readyState attribute of XHR object.
And it's a bookmarklet, so it can be inserted in at any loading stage.
Added later: Anyway, it looks like it's not a big issue for me. Because this attribute will be added in FF3.6, and it does not break things badly in Firefox, when you manipulate on unfinished DOM (unlike IE).
No, it's not possible. Sorry. But here's what you can do. If you can't test for stuff you want to be there before acting:
window.setTimeout(function () {
// do your stuff here
}, 0);
(This will definitely do it after the page renders, but it might be after onload, not after DOMContentLoaded.)
If you do know how to test for what you're looking for:
(function () {
if (/* test if what you're looking for is there */) {
// do your stuff
} else {
window.setTimeout(arguments.callee, 0);
}
})();
This will do it immediately, unless whatever you're looking for is not there, in which case it will wait until after the onload event.
Edit:
Check out this solution.
What it does is, in the edge cases, checks if the last element of document.getElementsByTagName("*") is undefined or not. And that seems to work for him, even in Opera.
Can be executed? Just be notified of the DOM event and store its state. I don't see what your root problem is. Surely you could rip out the guts of this method and adapt it to your situation.
jQuery's way of doing it:
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", function(){
//do stuff
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
jQuery.ready();
}
});
// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( jQuery.isReady ) return;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
}
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );

Categories