Monday, February 19, 2018

on browser detection with javascript

wow. when it comes to using javascript to build custom web applications, if there was one thing i thought would be easy to do is have the app figure out what browser type is being used. nope.

many years ago when i first starting learning javascript, detecting the browser was pretty essential, because at the time browsers varied widely in how they implemented javascript. some behavior was different, some appearance was different, and on some browsers, some aspects of the language weren't supported at all. and this was long before handy libraries and frameworks like dojo and jquery.

these days? much, much better. but even still, occasionally you run into an issue, and if the limitation or bug is inside someone else's blackbox, you reverse-hack a workaround.



here's what i ran into, above.

drawing some of my own graphic labels on the map. i need the labels to sit on polygon masks that i'm also creating. the yellow masks up there always draw fine, but the labels vary.

so, come to find out that on some browsers (chrome, opera) the labels draw fine, on other browsers (msie, firefox, safari, edge) the label itself draws too low. luckily the API i'm using, i can apply an offset to juke the label to make it look better, but i need to know at runtime which browser is being used so that i can tell it how far to juke, if at all.

so i start googling around, and ran into some samples of varying age, and varying usefulness. not good enough to cover all my bases. some written for entirely different purposes, or otherwise mucked up with regex, or accounting for possibilities so exhaustively, to make the end result internationally bulletproof, but for me 90% unnecessary and tough to wean back.

then i figured javascript frameworks might help. i looked into things like jquery.browser (which its own doc says it's deprecated all over the place with no new references) and dojo/has and dojo/sniff, still issues left and right, then scope issues with wanting to have some of this code outside the AMD loader require statement, but probably my inexperience with those contributed to the problems. i need to learn how to wrestle with dojo better.

i even found this little gem on twitter:



rock solid advice no doubt, but feature detection doesn't really apply in my case since i'm not trying to call certain features or install extensions, etc. i just need to know the browser, so that i can go do my thing with the labels. i also tried an example that used ducktyping, which i suppose is a flavor of feature detection (trying to determine what something is, by testing what it can and cannot do: i.e., if it walks and quacks like a duck), and ran into more exceptions than things that actually worked. at any rate...

so i finally went brute force and found that the dom's own navigator class has a .userAgent property that contains a lot of gobbledyguk, but enough there to do some string parsing.



browsers like opera, firefox, and safari, no problem. the .userAgent returned by those browser has enough uniqueness to it.

the example above is what chrome browsers return, and while this string contains *both* the words "chrome" and "safari", the safari browser's has "safari" but not "chrome", so if i check for "safari" first, then overwrite that with "chrome" later if the browser is chrome, then i'm good. (i guess i could've used a switch condition with some fall-through), but at any rate, here's what i ended up with:


and since no workaround is so nice that microsoft internet explorer can't find a way to toss a wrench in, guess what... the javascript inside IE doesn't support the string object's .includes method!! argh. so i tried .indexOf and other similar methods, to no avail.

so i'm making my kludge a little kludgier and i'm deciding to avoid the problem for now by assuming that if i don't proactively find the other browsers, i can reactively assume "msie". i'm sure that won't hold up in the long run, but until i find a better way, i'll see how far i can get with it. oh, and don't miss the forced use of try...catch, because if you try to call .includes on an IE browser, the whole thing craps out.

i'm all ears if anyone out there has a better way to do browser detection. i'm better just about anyone reading this does. (hopefully)

end result:




No comments:

Post a Comment