hashchange event not being fired on mobile Chrome (Wordpress site) - javascript

In my Wordpress site, I've created a Modal shortcode, which opens a modal when the modal's "name" is in the hash part of the location.
For instance /#contact-us will open my "contact us" modal.
To do this I have a hashchange event listener on the window, using jQuery, as so:
$(document).ready(function () {
$(window).on('hashchange', function () {
openModal();
});
});
On my laptop, this works pretty fine.
The problem is that when I try it on my mobile phone (Nexus 5 - Chrome & Firefox), and even when I use Chrome's devtools emulator, when clicking on an anchor with a href="#contact-us", it won't work - The hash in the url changes but the event handler is not being called.
The weird thing is if I manually add a hash to the url, the event handler will be called.
I thought there might be another handler that is stopping the propagation or something like that, so I tried using jQuery's _data function (as mentioned here) to see if there are any handlers, but couldn't find any.
So I guess my question is, why isn't this working? and what else can I do to find out where the event is "getting lost"?

Related

Popstate not triggering on Chrome for Android when clicking the back button

Upon clicking the back button in the browser, I would like to prevent the default behaviour of going one page back and instead do an action. I'm using the "popstate" event listener. The following function (I'm using Vue 2) works in all major browsers and even in Firefox for Android, but when I test it in Chrome for Android, it simply goes back one page without popstate being triggered at all.
mounted() {
history.pushState(null, null, <current-url>);
window.addEventListener("popstate", () => { alert(1) });
}
I tried wrapping the popstate event inside the load event and giving it a timeOut of 0, but it still didn't work specifically in Chrome for Android. The version I'm testing on is 93.
I did some more research and it seems that Chrome won't let you use popstate if there is no user interaction first. As long as you click on something or scroll down on mobile, popsate will work, otherwise it won't. I tried to simulate user interaction with click(), but that didn't work either. It seems Chrome wants genuine user interaction. I also realized this is sort of a duplicate of: Chrome popstate not firing on Back Button if no user interaction

InAppBrowser loadstart event not firing / scope issues

(This is a phonegap app, for iOS & Android, using JS/HTML/CSS)
I open up links I want to use the inappbrowser using the class selector, 'external'. So I have the below code to open up those links:
$("body").on("click", "a.external", function(){
var thisHref = $(this).attr("href");
appBrowser = cordova.InAppBrowser.open(thisHref, '_blank', 'location=no, zoom=no');
appBrowser.addEventListener('loadstart', function(event) {
if (event.url == "XXXXX") { appBrowser.close(); }
});
At the external URLs themselves, I set up links that link to 'XXXXX' that should close out the inAppBrowser. Everything works 100% on the Phonegap Desktop emulator, but when I install the .apk or .ipa files on actual devices, loadstart doesn't get fired EXCEPT for the first initial click within the app.
This leads me to believe it's a scope issue, since it looks like the listener only picks up when the loadstart occurs directly after a click to a.external. (P.S. appBrowser is defined globally [var appBrowser; at top]).
I'm not exactly sure how to arrange the code so that the listener gets attached, and continues working the entire time. I have tried placing the addEventListener on its own, within deviceready function, or the whole thing within deviceready (neither work).
So I'm hoping there's something simple I'm missing here, and it is indeed a scope issue. Strange though that it works as is on the emulator, but only on the first click on the devices themselves.
Thanks!
Here's the relevant portions of how I have things setup in my phonegap project using InAppBrowser, which if I understand your question correctly is similar to how you want your setup.
phonegap-bootstrap.js
onDeviceReady: function() {
window.open = cordova.InAppBrowser.open;
}
when opening links
window.open(url, '_system', 'location=yes');
I suppose you don't need the location flag, but that keeps the URL bar when you open your new window. Hope that helps, I remember having to figure this out at some point, but any greater explanation I might have has been lost in my memory.

How can I ignore window.onpopstate on page load?

I'm playing with window.onpopstate, and there is a thing that annoys me:
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.
source
I tested it, and yeah, in Chrome and Safari 5.1+ the popstate event is fired on page load, but not in Firefox or IE10.
The problem is, that I want to listen only to popstate events where user clicked the back or forward button (or the history was changed via javascript), but don't want to do anything on pageload.
In other words, I want to differentiate the popstate event from page load from the other popstate events.
This is what I tried so far (I'm using jQuery):
$(function() {
console.log('document ready');
setTimeout(function() {
window.onpopstate = function(event) {
// Do something here
}, 10);
});
Basically I'm try to bind my listener function to popstate late enough to be not bound on page load, only later.
This seems to work; however, I don't like this solution. How can I be sure that the timeout chosen for setTimeout is big enough, but not too big (because I don't want it to wait too much).
I hope for a smarter solution!
Check for boolean truth of event.state in popstate event handler:
window.addEventListener('popstate', function(event) {
if (event.state) {
alert('!');
}
}, false);
To ensure this will work, always specify a non-null state argument when calling history.pushState() or history.replaceState(). Also, consider using a wrapper library like History.js that provides consistent behavior across browsers.
I had a similar problem and i had to validate to make sure if page was loaded completely.
I used something like this :
var page_loaded = false;
window.onpopstate = function(event){
if(!page_loaded){
page_loaded = true;
return false;
}
//Continue With Your Code
}
To react on popstate event, you need to push some state onto the session history.
For example add this line to the document ready section:
history.pushState(null, null, window.location.pathname);
Not ideal, but it works in Chrome, Firefox and other browsers as well.
Then the event is fired correctly when user clicks on Back or Forward button, also when history.back(), history.forward(), history.go() methods are called manually. Each time when popstate has been invoked, you have to push another state again to make it working.
See also:
Single-Page Apps and HTML5 pushState
How to Detect Browser Back Button event - Cross Browser
It seems none of the browsers are emitting the event on page load any more as of today:
Browsers used to handle the popstate event differently on page load, but now they behave the same. Firefox never emitted a popstate event on page load. Chrome did until version 34, while Safari did until version 10.0.
Source: https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent

Using onpopstate in an Chrome Extension for Facebook

I'm trying to create a Chrome plugin for facebook and I'm using onpopstate event to check when the user goes to another page. The only problem is that the onpopstate doesn't fire.
This is the (simple) code I'm using:
window.onpopstate = function() { console.log('pop'); };
this is a screen of the problem:
As you can see the pushState code is called, but the onpopstate listener is not.
Do you know what's happening here?
#enhzflep's answer is in the comments above and not immediately obvious. From MDN:
Calling history.pushState() or history.replaceState() won't trigger a popstate event. The popstate event is only triggered by performing a browser action, such as clicking on the back button (or calling history.back() in JavaScript), when navigating between two history entries for the same document.
In other words, the onpopstate event shouldn't be firing in this case.

hotkey plugin opens new window even if pop-ups are blocked?

I want to open new window if "F2" pressed. Below code gives me newWindow is null error message in firefox. If I don't use pop-up blocker it works. The same in IE. It work in chrome even with pop-up blocker on.
using jstree pre 1.0 stable
hotkeys: {
"f3" : function () {
url = "http://www.vse.cz";
var newWindow = window.open(url, '_blank');
newWindow.focus();
return false;
},
Q1: Can I make it work for all browsers so users don't have to change their settings when using hotkeys plugin?
Q2: How come Using JavaScript instead of target to open new windows works without any troubles in firefox? Is that because it's a link and not using hotkeys plugin?
My understanding is that the script from above page somehow
manipulates what happens
when user clicks a link. It changes the properties of the click so
browsers "don't know" that it's new window so pop-up blocker is
bypassed.
In my case I use pure js function triggered by something else, not by
a user click. And that 'my function' doesn't changes properties of any html objects. I think this is the difference. I am not sure if I am
right here.
Unfortunately, there's nothing you can do to open a new window on a keypress (other than disabling the popup blocker).
The way that the popup blockers in IE, Firefox and Chrome work (from a high level) is by the browser (upon encountering a call to window.open) walking up the JavaScript call stack to determine if the current function is—or was called by a function that is—an event handler. In other words, it finds out if the current function is executing because the user did something that triggered a DOM event.
If so, then the popup is allowed; otherwise it is blocked. However, the question of which events qualify as "popup-allowing" vary by browser. By default in Mozilla, only change, click, dblclick, mouseup, reset, and submit qualify. (I assume IE is similar.)
Functions that are event handlers for any other type of event – such as keydown/keyup/keypress in your case – do not qualify for special popup-allowing treatment, which means your popup is blocked and is why your call to window.open returns null.
Chrome, however, does consider the keydown event eligible for allowing popups to be opened, which is why your script works in that browser.
Here's a reduced example to demonstrate how this works. This demo:
Defines a function called spawn() which calls window.open to open a popup.
Calls spawn() immediately as the page is loaded. This is blocked by all browsers since the call is made from the global scope; it is not called from an event handler.
Attaches a function to window.onkeydown which calls spawn(). If you press any key in Chrome, the popup will open because it allows popups from keydown handlers. In IE and Firefox, the popup will be blocked becuase those browsers do not allow popups from keyboard events.
Attaches an event handler to the link which calls spawn(). When you click the link, the popup will be allowed in all browsers because the call to window.open can be traced back to an event handler for a click event.
As you can now see, nothing goes on to manipulate event properties or "trick" the browser in to not knowing that there's a new window. The behavior of popups being allowed to open from link clicks is by design, the theory being that if you've clicked on something, it's likely that you want to see whatever is in the popup. However, when a call is made to window.open from a place where you've not done anything (such as the global scope), it's likely you do not have any interest in whatever [ad] is in the automatically-launching popup.
In this way, popup blockers prevent annoyances (automatically launching ads) while still allowing pages to open popups at the user's request.

Categories

Resources