IE not firing popstate when hashchange happens - javascript

I have page that is doing the routing on clientside, using history API & push/popstate. Which works just fine on all the modern browsers. (search engines will be supported by node.js prerenderer)
However, I recently bumped into issue where IE doesn't fire popstate on hashchange while, while pushstate with urls works just fine, including IE11.
For example, like so...
$(document).on('click', 'a', function(e) {
e.preventDefault();
History.pushState({}, '', $(this).attr('href'));
});
...which correctly fires...
$(window).on('popstate', function() {
console.log('url changed');
});
According the W3C spec, the hashchange should fire popstate as it's changing the current history. However, when I add in hash links (<a href="#hashchange">...), clicking that on IE, nothing fires. :/
I wouldn't want to do IE detecting (as nowadays there are so many browsers which might fall in to the same pit of doom), rather than using feature detection. However, as history (popstate/pushstate) works just fine the rest of the way I can't even detect the issue on missing push/popstate...
if(!window.history || !window.history.pushState) { ...
... and use the hashchange instead. :/
Any thoughts?
PS. As a bonus, using jquery.history.js (jquery wrapped version of history.js) with hashtag url blows the whole thing up.
http://localhost/routetest/index.html#/page1/1234
becomes
http://localhost/page1/1234
... ??? :/

This is a known issue in IE11 and all Internet Explorer browsers before Edge.
See this link https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/3740423/. The Microsoft response is the last post in this issue report, and notes the newest version that is working.
All versions of IE will display this behavior, and hacking/monkey-patching the correct behavior back into the event framework is probably the only way to make it work reliably. This means you will likely need IE specific logic if you want to implement it yourself.

Try using a polyfill for History API for better support https://github.com/browserstate/history.js

In IE 10 and 11 the popstate event will only be fired for a history item after the state has been set with history.pushState or replaceState, including when it is set to null, and only when traversing between two items that have had state set. Therefore, it is necessary to set the state for a new history item in the hashchange event. Once the state is set, the popstate event will fire when the user navigates through the browser history.
https://developer.mozilla.org/en-US/docs/Web/API/History

Related

Javascript/JQuery drop event not firing in Internet Explorer IE 11

I'm dragging and dropping images from a different browser tab into the tab for my web page. My event handlers for the "drop" event are working in every other desktop browser except Internet Explorer 11.
IE just navigates away to the URL of the image I dropped, rather than firing the "drop" event and letting my JS code do what it wants with it (as happens in Chrome, Firefox, Opera and Safari, on Windows 7). Code is below. Note none of the alerts listed in the code fire.
I even followed the advice given on Microsoft's page here: https://msdn.microsoft.com/en-us/library/ms536929(v=vs.85).aspx
regarding cancelling the default action of "dragenter" and "specifying window.event.returnValue=false in both the ondragenter and ondragover event handlers" (note: other browsers didn't require me to have a dragenter event handler)
$(window).on("dragenter", function(event) {
alert('drag enter');
event.returnValue = false;
event.preventDefault();
event.stopPropagation();
});
$(window).on("dragover", function(event) {
alert('drag over');
event.returnValue = false;
event.preventDefault();
event.stopPropagation();
});
$(window).on("dragleave", function(event) {
alert('drag leave');
event.preventDefault();
event.stopPropagation();
});
$(window).on("drop", function(event) {
alert('drop');
event.preventDefault();
event.stopPropagation();
var imageSrc = $(event.originalEvent.dataTransfer.getData('text/html'))
.filter(function(i, elm){return $(elm).is('img');}).attr('src');
// Now do something with the imageSrc URL:
});
Many thanks for any suggestions!
It is working fine in IE Browser Version:11.0.40 for jQuery 2.2.4 version.
Please check your jQuery version
Note: for me event has been fired for two times when dragging image from desktop to IE 11 browser.
Please find Demo link.
Edit:
Interesting what I've got here (S.O question/answer), they had a similar problem dragging between two Internet Explorer 11 windows, on the same domain. So one more reason, if they are from different domains. He quotes:
so far I understood that this will work on Windows 10 MS browsers with
at least 1607 as version
First, this is by no means intended to be an answer to this question, it merely serves as a group of points that may help build a final answer to this puzzling problem
Two cases scenario
On the same domain
Tested when both pages are on localhost, Those events has fired normally :
you will have to change getData('text/html') to getData('text') because IE support only that, 'URL' or files
so you need to set setData() from the original page accordingly
(Generally, if the dragged markup is an image without any links, you're fine the getData('text') gives you the attribute src of the image)
On different domains
Here is the part where this is not much of an answer, the following points have been tried and are given here to be retested, tweaked or expanded in order to find a solution. As a final thought that I'm putting here first: may be this is not possible, because as you may already know, dragged markup can have inline scripts, making the target vulnerable to XSS attacks. It's not very unlikely that hackers have tried to make it happen (roughly as I'm doing right know) and each time Microsoft has counteract it.
As the original poster pointed out the use of returnValue=false is pointless. I've tried it on the original event event.originalEvent and with event as a window's event and as the handler parameter.
You may think since I've mention domain that this is a cross domain issue (very legitimate) here's what I've tried in PHP:
header("Access-Control-Allow-Origin: *");
After IE had been known for been vulnerable to XSS attacks, it may have taken drastic measures against it in IE 11, so reverting to a previous version's behaviour of it, IE9 for instance :
header('X-UA-Compatible: IE=EmulateIE9');
header('X-UA-Compatible: IE=9');
N.B The following point is not intended to be a viable solution (at least not from a developer's perspective) it is an attempt to narrow down the possibilities of the origin of the problem
You may want to try Internet Explorer's :
internet options>Custom level...-->miscellaneous--> under the label 'allow the dragging of content between separate windows' --> check enable
Or Internet Explorer security zones registry entries for advanced users or using this reference
Notice that for the purpose of testing you can make cross domain dragging between IE and Firefox/Chrome back and forth with DataTransfer behaving roughly as between two IEs on the same domain.

Window binding not working in Firefox

my script reads something like this:
$(window).bind('popstate', function() {
//some code
//few more lines of code
});
This function works perfectly as intended in Chrome and Safari browsers. But Firefox for some reason ignores this function and does not work as intended.
Instead of using:
$(window).bind('popstate', function() {
//some code
//few more lines of code
});
You can use:
window.onpopstate = function() {
//some code
//few more lines of code
}
As firefox is using W3C defined rules for history API, so you have to use this for firefox and it works in chrome, safari and other browsers as well.
Note that just calling history.pushState() or history.replaceState()
won't trigger a popstate event. The popstate event is only triggered
by doing a browser action such as a click on the back button (or
calling history.back() in JavaScript).
Browsers tend to handle the popstate event differently on page load.
Chrome and Safari always emit a popstate event on page load, but
Firefox doesn't.
https://developer.mozilla.org/en-US/docs/Web/Reference/Events/popstate
Are you saying Chrome and Safari fire the event on page load or when the browser's back button is clicked? If the former, it's because Chrome/Safari are out of compliance with the HTML5 specs => the event should never be fired on page load. Up-vote https://code.google.com/p/chromium/issues/detail?id=63040 to get Google to fix this.
Please do Check that if you have coded window.load() more than once OR have called .onload() more than one time. This probably may work for IE but not for Chrome and fireFox.

Catch "Back" event in browser and load different content

I've been working on a project using the hashbang (#!) method to skip though pages. Basically there is only 1 page, and when you click to go to a diffrent page, you stay on the page, but the URL changes, e.g. from index.html#home to index.html#about and new content is loaded via AJAX/JSON. All works well, but if I go "back" (or forward) in the browser, only the page in the URL changes, but my jQuery isn't fired to reload the content.
What I need is some code that will handle both the back and forward actions in all browsers, so that I can fire the function to load the page from jQuery. How do I do this?
Why reinvent the wheel? History.js is a great & well-maintained jQuery plugin that supports the new HTML5 History API and falls back gracefully to using hash URLs instead when the History API isn't supported. Works in just about every browser (even IE 6).
Take a look at the hashchange event. It fires when the hash is changed. However, you should only do this for Internet Explorer 8 support.
Internet Explorer 7 does not support hashchange, so you can't rely on that. As for Internet Explorer 9, it (along with Chrome, Safari and Firefox, of course) supports the History API, which you should be using instead. It keeps your URLs clear, short and semantic, while enabling elegant Back/Forward button support.
There is a jQuery-Plugin that seems to be doing exactly what you want.
http://www.asual.com/jquery/address/
It was the highest voted answer for the questing What is the best back button jQuery plugin?

History.js onstatechange in IE7 does not work

I integrated History.js and this piece of code runs on URL change:
History.Adapter.bind(window,'statechange',function(){
var State = History.getState();
alert(State.url)
showPage(State.url);
});
It works well in all browsers except IE7 (compatibility mode of IE8). I thought History.js would handle this.
Is it true that IE7 does not understand onStateChange event? What window event can be used for this case?
From the notes on compatibility it states:
MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
https://github.com/browserstate/History.js/

Opera: Detecting back, forward, refresh and close events

I'm currently working on a jQuery plugin that tracks a visitors mouse behavior. Movements, clicks, scrolling and resizing are all recorded and sent, via Ajax, to a location where this data is parsed and stored.
Originally, the data is sent to a script when the user leaves the page. By 'leaves' I'm referring to refreshing, going back and forth though history, closing the window/tab and going to a different address.
The solution works in all browsers EXCEPT for Opera. I'm using jQuery's 'unload' event which isn't supported by Opera at all. Neither is onbeforeunload or onunload.
The question is, how do I implement this kind of functionality for Opera browsers?
One solution I had was to make special use of a 'polling' feature I created. This feature allows you to specify an interval which pushes the content to the server every 'x' seconds. Setting this to 1 second specifically for Opera browsers would probably solve this issue, but it's an awful amount of overhead and the requests aren't always completed in sequence, etc ...
Any suggestions or am I only stuck with the above option?
Thanks!
I suppose I could just link you guys to the plugin source. http://www.thedrunkenepic.com/junk/jquery.mousalytics.js
Regarding the code linked above, adding:
if(window.opera)
{
options.interval = 1;
}
On line 89 works great. My only concern is overhead, so I'm still looking for a more elegant solution.
According to http://bytes.com/topic/javascript/insights/799229-browser-quirk-onload-onunload-do-not-fire-back-forward-refresh-opera, Opera never really fires onload / onunload events, so functionality like this isn't possible without hacks.
http://dev.opera.com/articles/view/efficient-javascript/?page=4 seems to confirm this, and basically states that opera tries to maintain the state of the page across requests.
On further investgation, http://unitehowto.com/Onunload indicates that it might be possible with opera.io.webserver.addEventListener('_close', onunload, false); (where onunload is a previously defined function), however it also indicates that this functionality is not consistent across all versions of opera, and might not work at all.
I think that your best option is probably to use the polling option for Opera, or possibly use a server-side check for the current page and where it falls in the history queue.
Does adding this line of JavaScript work for you?
history.navigationMode = 'compatible';
Source: http://www.opera.com/support/kb/view/827/
I've had the same problem and this saved my day:
if( typeof(opera) != 'undefined' )
{
opera.setOverrideHistoryNavigationMode( 'compatible' );
history.navigationMode = 'compatible';
}
More info about this problem can be found at: http://www.opera.com/support/kb/view/827/

Categories