I'm aware of the fact that the FileReader Object is not available in Safari 5.0.5. I have a script that uses it and thought that i'd just be able to detect whether the object exists to run some alternate code, as is suggested here,
http://www.quirksmode.org/js/support.html
So my code is,
if( FileReader )
{
//do this
}else{
//the browser doesn't support the FileReader Object, so do this
}
The problem is, i've tested it in Safari and once it hits the if statement i get this error and the script stops running.
ReferenceError: Can't find variable: FileReader
So obviously that's not the best way to deal with it then? Any idea why this doesn't work?
I believe in your case you can get away with a simpler check:
if(window.FileReader) {
//do this
} else {
//the browser doesn't support the FileReader Object, so do this
}
check for the type if you really wanna be granular and picky.
You can write if (typeof FileReader !== "undefined")
You can also use the Modernizr library to check for you.
Or you can do something like this.
if('FileReader' in window) {
// FileReader support is available
} else {
// No support available
}
Related
I'm looking for a neat way to detect whether postMessage in the browser supports the sending and receiving of objects or just strings. I figure that someone out there must have wrote something that does this but I have not managed to find a solution.
I'm using postMessage to send data to/from a WebWorker. Whilst detecting whether the browser supports workers is straight-forward, detecting whether objects can be send via postMessage has proved more difficult.
I'd like to write a simple detection function. So, if the browser supports the sending of objects to use that. If only strings are allowed I can fallback to using JSON.stringify(). I'll probably assign the function to a dojo/has test (although this is not relevant to the question/answer).
What have other people done to solve this problem? Any advice would be great, I'm new to both WebWorkers and postMessage. Thanks in advance.
I found an even easier way to detect if postMessage only supports strings or if it supports other types. Simply add a custom toString-method on the object. When trying to send an object with postMessage in IE8 and IE9 they will be converted to a string with the toString-method on the object. Since browsers that support sending objects doesn't call toString we can use this to our advantage. This test is not async, so you'll get the result instantly. Haven't tested this with web-workers, but I suppose you can use the same technique.
var onlyStrings = false;
try{window.postMessage({toString:function(){onlyStrings=true;}},"*");}catch(e){}
console.log("Browser only supports postMessage with strings? " + onlyStrings);
Tested in IE8, IE9, IE10 and latest version of Chrome, Firefox, Safari and Opera:
http://jsbin.com/igowoFaj/1/edit?js,console
Update: Did a BrowserScope test with many more tests and browsers. Conclusion is that it's safe to send clonable objects, arrays, numbers, pixel data and array buffers if onlyStrings is false. In theory all browsers that allow sending objects should use the structured clone algorithm, but the Android browser and Opera Mobile has quirks. The BrowserScope test result is a bit hard to read, because a 0 for send_xxx is only problematic if the browser actually has support for that type, so check supports_xxx too. If they are equal it's ok, but it's a bug if the browser has support but can't send (when onlyStrings is false).
You could try to perform an action BEFORE resuming your script. You could try this:
dummy_task.js
self.onmessage = function(event) {
self.postMessage(event.data);
};
javascript
workerSupportObject(callback);
function workerSupportObject(callback) {
var callbackIsCalled = false; // to make sure callback isn't run twice
var worker = new Worker('dummy_task.js'); // create a worker
// create event
worker.onmessage = function(event) {
// if the value is the same as we sent, it probably works
if(!callbackIsCalled) callback.call(null, event.data.value === 'dummy');
callbackIsCalled = true;
};
try {
// send dummy JSON data
worker.postMessage({'value': 'dummy'});
} catch(e) {
// oh... an error... clearly that's a no.
if(!callbackIsCalled) callback(null, false);
callbackIsCalled = true;
}
}
function callback(objectSupported) {
console.log('Worker supports objects: ', objectSupported);
}
I wanted to know the same thing. I created this script to detect if an object could be passed in postMessage by a simple callback to the current window. You will see IE 9 return false, IE 10 returns true.
http://jsfiddle.net/milesplit/DvqqH/
var supportsPostObject = false;
(function(){
var callback = function(e) {
supportsPostObject = (typeof(e.data)!='string');
};
(window.addEventListener) ?
window.addEventListener('message', callback) :
window.attachEvent('onmessage', callback);
('postMessage' in window) && window.postMessage({}, '*');
})();
setTimeout(function(){
alert(supportsPostObject);
}, 0);
postMessage also works between iframes; assuming that the behavior is the same between workers and frames, you should try the following or something like it:
<html>
<body>
<iframe id='if'>
</iframe>
<script>
var iframe = document.getElementById('if');
var iframeScript = iframe.contentDocument.createElement("script");
iframeScript.appendChild(
iframe.contentDocument.createTextNode(
'window.addEventListener("message", function(e) {console.log(e.data);}); console.log("listener attached");'));
iframe.contentDocument.body.appendChild(iframeScript);
iframe.contentWindow.postMessage("asdf", "*");
iframe.contentWindow.postMessage({'whatAmI': 'an object, maybe?'}, "*");
</script>
</body>
</html>
You may need to replace console or console.log to be able to see results, but on Chrome, this gets me
listener attached about:blank (1):1
asdf about:blank (1):1
Object {whatAmI: "an object, maybe?"} about:blank (1):1
when I save it to a local file and open it up.
The jsfiddle version (and the version which uses an actual worker) are left as an exercise for the reader. :)
So I know $.browser has been deprecated and "frowned upon", since jQuery 1.3, but it continues to exist & work in the code.
It's still using the plain javascript: navigator.userAgent to determine the browser being used, as well as the version.
Now is there something about these I don't know about navigator itself, that I shouldn't be using either $.browser or plain vanilla JS to get the browser/version? I just want to make sure when they have IE8 (for example), they really do have it, and I'm not processing the wrong code.
What other alternatives do we have for browser sniffing? I know about $.support, I use modernizr, but sometimes I need just need the down and dirty browser version, instead of seeing what the browser is capable of handling (I think that is a completely different problem solver).
You kind of answer the question yourself. The ideal is to check for feature support. As more browsers and devices come onto the market this approach should scale.
However if you want to do something 'down and dirty' then browser detection of course works, but only so far as you will know your code works in the existing set of browsers (or even just those you've tested your code with).
Generally it's recommended not to try to guess what the browser is but to check if a function is available. There are too many browsers and variants.
To check if a function is available, you simply do this :
if (!Array.prototype.map) {
// not available, shut down computer !
If a "must" to know which browser on the page for me, I use this personally;
(function() {
var re_browsers = {
firefox: /firefox\/([\d\.]+)/,
chrome: /chrome\/([\d\.]+)/,
safari: /webkit.*?version\/([\d\.]+)/,
opera: /opera.*?version\/([\d\.]+)/,
ie: /msie\s+([\d\.]+)/
// ...
};
var ua = window.navigator.userAgent.toLowerCase(), k, re, browser = {};
for (k in re_browsers) {
if (re = re_browsers[k].exec(ua)) {
break;
}
}
browser[k] = true;
browser["version"] = parseFloat(re && re[1]);
browser["versionOrig"] = re[1];
jQuery.extend({browser: browser});
})();
Is there any way to check a browser whether it supports 'HTML5 History API' using JavaScript.
Do I have to check all the browsers and its versions with a long list of condition in if statement.
Or simply like checking any object of function using 'if' statement is enough???...
Checking for the existence of a pushState() method on the global history object should be sufficient.
function supports_history_api() {
return !!(window.history && history.pushState);
}
For more general HTML 5 feature detection I'd look at Modernizer
http://diveintohtml5.info/detect.html#modernizr
This will insulate your code from the messy specifics of each test, making the code more readable and less error prone. With the Modernizer script on your page you'd just do:
if (Modernizr.history) {
// history management works!
} else {
// no history support :(
// fall back to a scripted solution like History.js
}
Checking for history.pushState and history.replaceState objects existence should be sufficient, as it's generally sufficient with feature detection in general.
You can use canisuse.js script to detect if your browsers supports history or not
caniuse.history()
You can check weather or not a function is registered:
if (typeof history.pushState != 'undefined') {
//Enabled
}
Then just replace //Enabled with whatever you wish to do if it's supported.
Sometimes some developers forgot to remove debugger; in javascript code, and it produce javascript error on IE.
How can you check (like for the console: if(window.console){console.log('foo');}) if a debugger exists?
BTW: I don't want to detect if the browser is IE, I want a generic method if possible
Thanks,
You cannot.
The best solution would be adding a hook to your version control system to prevent code containing debugger; statements from being committed/pushed.
Asking your devs to search for debugger; or at least have a careful look at the diff before committing is also a solution - but not as effective as hard-rejecting in the VCS.
You could attempt to compile a function that declares debugger as a local variable. If debugger is reserved as a keyword, the JS engine will throw an error which you can catch.
var debuggerIsKeyword = false;
try {
new Function("var debugger;");
} catch(e) {
debuggerIsKeyword = true;
}
However I'm not sure that knowing whether a keyword exists or not is actually helpful.
Maybe the safest approach is to have a global include file for all your projects that stubs out the debugger if it doesn't exist:
if (typeof debugger == 'undefined') {
window.debugger = null;
}
That way calls to debugger just become a reference to null. which is harmless. Seems like a better approach than expecting forgetful developers to wrap each debugger call in an if statement.
The same approach works for console.log, etc.
EDIT: As AndrewF points out, debugger is actually a keyword, not a global, so this won't work. The same effect can be achieved using the following without throwing an error:
window['debugger'] = null;
Haven't tried it for lack of an IE, but this should work:
if (typeof console !== 'undefined') {
console.log("logging enabled");
}
I'm trying to check if the browser supports onHashChange or not to hide some code from it if not, in this way:
if(window.onhashchange){
...code...
} else {
...other code...
}
I tried this too:
if(typeof window.onhashchange === "function"){
alert("Supports");
} else {
alert("Doesn't Supports");
}
As described on Quirksmode this should work but if I do an alert for example in true state in Safari than alerts me but Safari is not supporting onHashChange :S
What's the problem with it? If I'm not on the right way how should I check it?
You can detect this event by using the in operator:
if ("onhashchange" in window) {
//...
}
See also:
onhashchange - MDC
Detecting event support without browser sniffing
Emulating onhashchange without setInterval
Be warned that you're better off using feature detection rather than existence inference (such as "onhashchange" in window).
#xkit explained to me a good feature test to work around the fact that although IE7 doesn't support onhashchange it would still return true for existence inference such as if("onhashchange" in window){/code/} when using IE7 Standard Document Mode in IE8.
What #xkit suggested was setting a flag (such as var isSet = true;) within a handler function for the onhashchange event. Then changing window.location.hash using JavaScript and see if the flag was set.
It's likely that the version of Safari that you're using has added support for the onhashchange event since the time that that Quirksmode article was written. Tests should still be valid; try it in other browsers you know not to support the event.
Edit: also, you should use the method described by #CMS instead, as the event will not contain a function by default; thus both of those tests will fail.
if (window.onhashchange !== undefined) alert('Supports onhashchange');