IE calls functions twice on ajaxified website - javascript

I have strange problem for which I can't think of a solution. I have written some Javascript code to load some content through a AJAX call which also does some animation. To make the website functional I use jQuery with History.js. This is the script:
(function (window, undefined) {
getContent(true); // Function that gets the initial content via AJAX and does some animation
// The parameter specifies that the call to the function is onload
History.Adapter.bind(window,'statechange',function(event){
getContent();
});
function getContent(onload){
if(onload == true){
// Do onload stuff. Only slightly differs from other event calls
// If there is no state given define default one ie 'home'
alert('onload event triggered'); // For debug purposes
} else {
// Do other event stuff
alert('click event triggered'); // For debug purposes
}
}
somelinks.on('click',a,function(){ // Setup some eventlisteners that push the state });
})(window);
In browsers that support the HTML5 History/State API (Firefox, Chrome) this works flawless. On a load or reload of a specific url or on a click event the function does its work.
In IE it also works (with hashes ofcourse), however when I reload a page (ie example.com/#/test) the first as well as the second 'getContent()' function. So in Firefox a reload triggers the onload event alert, but in IE the onload event and the click event alert are triggered.
What I need is a way of structering my code or a logical check to prevent IE from calling the second getContent(). I've searched for similar problems (keywords: IE, History.js, etc.) but nothing to be found.
Hope somebody can help me with the problem.

(function (window, undefined) {
var getContentOK = true;
getContent(true);
History.Adapter.bind(window,'statechange',function(event){
getContent(false);
});
function getContent(onload){
if (getContentOK === true) {
if(onload == true){
// Do onload stuff. Only slightly differs from other event calls
// If there is no state given define default one ie 'home'
alert('onload event triggered'); // For debug purposes
} else {
// Do other event stuff
alert('click event triggered'); // For debug purposes
}
getContentOK = false;
setTimeout(function () {
getContentOK = true;
}, 500);
}
}
somelinks.on('click',a,function(){ // Setup some eventlisteners that push the state });
})(window);
This will throttle the statechange event handler to only run getContent() once every 500ms.
Notice that I added some boolean flags, one to throttle the statechange event handler and one to mimic your onload variable. firstRun will output true on the first run and then false on each subsequent runs.
This is not as good a solution as figuring out what is happening with the History.js plugin but I have no experience with it so I can't say why IE is firing two events.

Related

Stop browser from sending certain JavaScript events

There is a website which fires a function on when the tab is blurred. I don't want that to happen.
Is there a way I can stop javascript from firing window.onBlur event?
From initial search, I have come to the conclusion that I need to override the default function of javascript, which can be done using userscript managers like Greesemonkey.
I tried the following script in Greesemonkey:
window.onblur = null
This doesn't seem to have any effect and the webpage behaves same as previously.
Have look at Event.preventDefault() and Event.stopPropagation() if it helps your case.
If you would like to override the function which is called on the event, you can simply redefine it and insert it using a script manager. For example:
var originalCallbackFunction = callbackFuntion;
callbackFunction = function() { // Redefinition
/* Do something else */
}

in chrome extensions how to trigger an event on deactivation?

I have a chrome extension which injects some DOM event listeners through the content scripts. I want to remove those event listeners from the DOM in the event that the user deactivates the plugins, is there a method to do so?
It's an interesting question. It has to do with a concept of "orphaned" scripts. I talk at length about those in an addendum here.
Problem is, as soon as the script becomes detached from the parent extension, Chrome APIs will fail. As such, detecting this is not straightforward.
There are many possible approaches:
Maintain an open port to the background page. The port will fire an onDisconnected event in case the background page ceases to exist.
This is an event-based approach - you will be able to react immediately.
But this has an important downside: maintaining an open port will prevent an Event page from unloading. So if you use a non-persistent background page, this is not optimal.
Periodically, or better yet - in the beginning of your handlers, try to do something with Chrome API. This will fail, and you can catch the exception and assume that the extension is orphaned.
Please note that this is pretty much undefined behavior. How Chrome API reacts can change over time.
function heartbeat(success, failure) {
try {
if(chrome.runtime.getManifest()) {
success();
} else { // will return undefined in an orphaned script
failure();
}
} catch(e) { // currently doesn't happen, but may happen
failure();
}
}
function handler() {
heartbeat(
function(){ // hearbeat success
/* Do stuff */
},
function(){ // hearbeat failure
someEvent.removeListener(handler);
console.log("Goodbye, cruel world!");
}
);
}
someEvent.addListener(handler);
Finally, there is a proposal to make a special event for this situation, but it's not implemented yet.
Specifically for updates when the extension is reloaded, you can make it inject scripts into existing pages and let old scripts know they should deactivate; however, since your question is about extension being removed, it doesn't help.
With the hard part done, actual removal of event listeners depends on how you added them, but should be straightforward.
onDisabled fired when app or extension has been disabled.
chrome.management.onDisabled.addListener(function callback)
EventTarget.removeEventListener() removes the event listener previously registered.
var div = document.getElementById('div');
var listener = function (event) {
/* do something here */
};
div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);
I think you don't need to this, since once your extension is disabled, your event listener will be removed and won't be injected.

Unbind events added by an external script loaded with jQuery's getScript function

I am loading an external script using jQuery's $.getScript function and it has something in it which I cannot understand:
if (!!window.addEventListener){ // FF
window.addEventListener('load', init, false);
} else if (!!window.attachEvent){ // IE
window.attachEvent('onload', init);
} else {
window.onclick = init;
}
Can someone please explain what this does?
I'm not sure but it adds some event listeners to check that the page is loaded.
But since I am loading the script with $.getScript function, I don't need those listeners anymore.
Is there a way to unbind them in the callback of the $.getScript function?
addEventListener adds event handlers, and attachEvent does the same for browsers that doesn't support addEventListener, which is just older IE.
The condition you have checks which one is available, and attaches an event handler to the window.onload event that calls the function init().
If none of the regular onload handler are available, it falls back to calling the init() function once the window is first clicked.
To remove the function, you'll have to try and do the opposite once the script has loaded.
You say you're using $.getScript, and that has a callback, so something like :
$.getScript('myscript.js', function() {
if (window.removeEventListener) {
window.removeEventListener( 'load', init, false );
}else if ( window.detachEvent ) {
window.detachEvent( 'onload', init );
}else{
window.onclick = function() {};
}
});
of course, it would be much easier and better to just remove the original event handler in the script you're loading if you no longer need that event handler.

Different actions with onbeforeunload

I am working on a simple chat script using Ajax and want to indicate when a user leaves the page. Have read several docs and found this works:
window.onbeforeunload = leaveChat;
function leaveChat(){
... my code
return 'Dont go...';
}
Unfortunately (and logically), if they cancel the exit, my code is still executed and they are flagged as leaving even though they are still on the page? It should only execute if the confirm leaving the page. Any suggestions?
I would use onunload, but it doesn't seem to work in any of my browsers (Chrome, IE).
First, you should add the event handler using:
window.addEventListener('beforeunload', function() {
// Confirmation code here
});
window.addEventListener('unload', function() {
// fire pixel tag to exit chat on server here
// UI interactions are not possible in this event
});
For further research:
unload event reference
beforeunload event reference
Window.onunload reference

What is the ideal way to handle window.onpopstate for all browsers?

For chrome the event fires on page load, but in firefox it fires the rightway, only when you press the backward or forward button. So how to write a script that works fine for all browsers?
I'd go browser detection on this one (in fact, I did). I'm using jquery's .data() to set a boolean flag to test against:
// chrome fires a popstack event on page load, so do a check before proceeding
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if( is_chrome && !$('body').data('allow-popstate-action') ) {
$('body').data('allow-popstate-action', true);
return false;
}
I've added this conditional clause in the function that is bound to the popstate event, so the first time it's called in Chrome (which is on page-load), it just exits the function without doing anything. Next time (prev/back buttons), it will work fine.
I'm stuck with an old version of jQuery on this project, so I couldn't use jQuery.browser.webkit, but you probably can.
A slightly more elegant way is to add a 1ms timeout before adding the popstate listener. Since the initial popstate will fire before any async code gets executed, your popstate function will work properly (only on forward/back actions):
window.setTimeout(function(){
$(window).on('popstate', function(event){
// do things
});
}, 1);

Categories

Resources