How do I detect support for contentEditable via JavaScript? - javascript

I've been searching for this for a couple of days now and so far, the best I can come up with is checking the list below. I really don't like to check for support based on User-Agent, especially since it can be spoofed. I've also heard of at least one instance where the list below is incorrect (noted below).
Is Internet Explorer?
Is WebKit? (But I've read that mobile Safari doesn't support it)
Is Opera?
Is Gecko and version >= 1.9? (meaning Firefox 3 or later)
Is there a better method based on testing for support directly via JavaScript, or is this pretty much the only way to test for support?

var canEditContent= 'contentEditable' in document.body;

The best way to check for a certain feature is to actually test for that feature on an element that you know should support it, like this:
if(element.contentEditable != null)
// then it's supported
or
if(typeof(element.contentEditable) != 'undefined')
// same thing.. but with typeof you can be more specific about the type of property you need to find

The best solution for my scenario (similar to yours) I came up with is below. It's not probably bulletproof, but covers most of the situations:
var ua = navigator.userAgent;
var android_version = ua.match(/Android ([0-9\.]+)/);
var div = document.createElement("DIV");
if( typeof(div.contentEditable) == 'undefined' ||
(/(iPhone|iPod|iPad)/i.test(ua) && /OS [1-4]_\d like Mac OS X/i.test(ua)) ||
(android_version!=null && parseFloat(android_version[1])<3 ) ||
(/(Opera Mobi)/i.test(ua))
) {
// doesn't support contenteditable
} else {
// supports contenteditable
}
You can test it out in this jsFiddle.
Notice: Depending on your needs and purpose, you might need to detect IE version as well, because it's support of contenteditable is ... "not ideal" :-) Most of the pains is dealt by super library Rangy.js.

bobince's answer works for the most part but, as has been said, you will need user agent sniffing to exclude iOS and Android versions that don't bring up the software keyboard. I'm currently using something like this:
function isContentEditable() {
var canEditContent = 'contentEditable' in document.body;
if (canEditContent) {
var webkit = navigator.userAgent.match(/(?:iPad|iPhone|Android).* AppleWebKit\/([^ ]+)/);
if (webkit && parseInt(webkit[1]) < 534) {
return false;
}
}
return canEditContent;
}
This should stop older iOS and Android devices from returning true. It still has one problem though: physical keyboards. If, for example, a device is running Android 2.3 but has a physical keyboard then the user will be able to use contentEditable but this function will return false. Physical keyboards are quite rare though.
More commonly, on some devices it may be possible for the user to bring up the on screen keyboard by pressing and holding the menu button. Obviously this isn't really something you should expect your users to know about.
You could mitigate these issues slightly by having some way for the user to manually override the sniffing part of the detection script. You could implement this in the isContentEditable function by adding an override check to "if (canEditContent)". However, Implementing the UI for this might present more of a challenge ;).

Related

How can I detect which browser is used with feature detection?

I wish to detect various browsers with feature detection in JavaScript from IE7-11, Chrome and Firefox. How can I do this>
As #dandavis said, look objects specific to the browser you need. For example:
if (!document.characterSet || !document.doctype || !document.defaultView) {
/**
* If the browser does not have these properties on the document,
* then it is probably IE8 or lower... Maybe.
*/
}

How to detect IE 11 with javascript in Asp.net

Hello I want to detect the Browser , IE 8 or more will be appropriate for me. For this i used following code but it fails for IE 11 . For other its detecting properly.
function getInternetExplorerVersion()
{
var rv = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null)
rv = parseFloat(RegExp.$1);
}
return rv;
}
Below is the link which also I tried but couldn't succeed.
You can explicitly detect IE11 with the following check (using feature detection):
if (Object.hasOwnProperty.call(window, "ActiveXObject") && !window.ActiveXObject) {
// is IE11
}
Explanation: All versions of IE (except really old ones) have window.ActiveXObject property present. IE11, however hides this property from DOM and that property is now undefined. But the property itself is present within object, so checking for property presence returns true in all IE versions, but in IE11 it also returns false for second check.
And, finally, hasOwnProperty is called via Object because in IE8 (and I believe earlier) window is not an instanceof Object and does not have hasOwnProperty method.
Another method, using userAgent string:
var ua = window.navigator.userAgent;
var versionSplit = /[\/\.]/i;
var versionRe = /(Version)\/([\w.\/]+)/i; // match for browser version
var operaRe = /(Opera|OPR)[\/ ]([\w.\/]+)/i;
var ieRe = /(?:(MSIE) |(Trident)\/.+rv:)([\w.]+)/i; // must not contain 'Opera'
var match = ua.match(operaRe) || ua.match(ieRe);
if (!match) {
return false;
}
if (Array.prototype.filter) {
match = match.filter(function(item) {
return (item != null);
});
} else {
// Hello, IE8!
for (var j = 0; j < match.length; j++) {
var matchGroup = match[j];
if (matchGroup == null || matchGroup == '') {
match.splice(j, 1);
j--;
}
}
}
var name = match[1].replace('Trident', 'MSIE').replace('OPR', 'Opera');
var versionMatch = ua.match(versionRe) || match;
var version = versionMatch[2].split(versionSplit);
This will detect any version of IE if its userAgent string was not spoofed.
There very rare cases when you actually need to use browser detection as described above. In most cases feature detection approach is preferable.
isIE11 = !!window.MSStream;
if(isIE11){
/* Something */
}
Use !(window.ActiveXObject) && "ActiveXObject" in window to detect IE11 explicitly.
To detect any IE version, use window.ActiveXObject || "ActiveXObject" in window instead.
As already stated - dont do browser detection, rather do feature detection. However as I see your script is an older version of a script the circulates around here.
This is the updated version that detects IE 11 aswel:
function getInternetExplorerVersion()
{
var rv = -1;
if (navigator.appName == 'Microsoft Internet Explorer')
{
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null)
rv = parseFloat( RegExp.$1 );
}
else if (navigator.appName == 'Netscape')
{
var ua = navigator.userAgent;
var re = new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null)
rv = parseFloat( RegExp.$1 );
}
return rv;
}
Is better for you if you avoid browser detection; if you need it here is a good explain from MS team:
In rare cases, it may be necessary to uniquely identify IE11 Preview. Use the Trident token to do so
User-agent string changes
For many legacy websites, some of the most
visible updates for IE11 Preview involve the user-agent string. Here's
what's reported for IE11 Preview on Windows 8.1 Preview: JavaScript
Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
As with previous versions of Internet Explorer, portions of user-agent
string vary according to the environment. Here's the string for IE11
Preview on Windows 7: JavaScript
Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
If you compare these strings to the ones reported by earlier versions
of Internet Explorer, you'll find the following changes: The
compatible ("compatible") and browser ("MSIE") tokens have been
removed. The "like Gecko" token has been added (for consistency with
other browsers). The version of the browser is now reported by a new
revision ("rv") token. These changes help prevent IE11 Preview from
being (incorrectly) identified as an earlier version. In general, you
should avoid detecting specific browsers or browser versions. The
assumptions underlying such tests tend to lead to false positive
results when browsers are updated. Instead, detect features as you
need them and use progressive enhancement to provide simplified
experiences for browsers or devices that do not support the features
you need. In rare cases, it may be necessary to uniquely identify IE11
Preview. Use the Trident token to do so
Link: http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx
More easy and efficient code and detect all versions of IE/Edge:
if(navigator.appVersion.indexOf("MSIE") != -1 || navigator.appVersion.indexOf("Trident") != -1 || navigator.appVersion.indexOf("Edge") != -1){
// is IE
}
I used the following code recently to detect IE in general and it worked just fine for IE 11 as well
var bs = document.body.style, isIE=false;
if ('msTransition' in bs) {
isIE = true;
}
The idea is to look for vedor prefix.
The 'use feature detection' mantra mystifies me. When you hit a bug, how can you determine what 'feature' is the culprit? Take for example this bit of code:
$('input[name^=qty]').keyup(function(e) {
if (this.value.match(/[^0-9\/]*/g)) {
this.value = this.value.replace(/[^0-9\/]/g, '')
}
});
It removes non-numeric chars from the input field as the user types. Works in FF, Chrome, and Safari. Does not work in ANY version of IE (up to 11, at least): any subsequent bindings on the input field will fail.
feature detect, feature detect, feature detect
<script>
if (!('querySelector' in document) //this should work in ie 9+
|| !('localStorage' in window) //ie 8+
|| !('addEventListener' in window) //ie 8 + (I think)
|| !('matchMedia' in window)) {//ie 10+
//do your redirect here
}
</script>
DO NOT DO BROWSER DETECTION! It will break, and it will cause you problems.
IE11 has a completely different User Agent string to previous IE versions; it not longer includes the "MSIE" text. This is why your detection code doesn't work.
It's important to note here that the reason they did this was deliberate. They wanted to break browser detection scripts like this.
It is possible to change your code to work with IE11, but I strongly recommend not doing this, as you'll probably have the same issue all over again when IE12 comes out.
So why did they want to break browser detection scripts? Simple: Because IE11 does not have the bugs of previous versions, and it has a lot of new features. So if you're doing browser detection because IE has certain bugs or missing features and you've got code to fix those issues based on the browser detect, then that code might actually cause worse problems in IE11 where the fixes aren't needed.
IE11 has broken your script, but the same logic applies to all browsers and all versions; detecting the browser and version is almost always the wrong thing to do.
If there are specific features that you want to support, but are missing in older IE versions (or other older browsers), don't use browser detection to work it out; you should use feature detection instead.
Feature detection means checking the browser to see whether it supports the particular features you want to use. The most common way of doing this is to use the Modernizr library. The docs on their site will guide you through setting it up.
There are a few bugs in older IE versions which are hard to detect, and for these few cases, it is valid to use browser detection as a last resort, but these cases are really only for IE6 and earlier. Maybe occasionally for IE7. But you've stated in the question that you're only looking at IE8 and later, so that should not apply.
Stick with feature detection; it's more reliable, better practice, and won't break suddenly when a new browser version is released.

Detect HTML5 Context Menu Support with JavaScript?

I didn't notice it in Modernizr's documentation but I imagine you create a menu element then check if it exists? My only concern is that the browser may support that but not type context. Any ideas? Thanks.
I have come up with a rather shoddy solution that returns true for Firefox as far as I can tell then returns false for Chrome, IE and Opera. Check it out:
// Detect context menu support.
function contextMenuSupported() {
var oMenu = document.createElement("menu");
// Kind of backwards but seems to work.
if (oMenu.type == "list")
return true;
return false;
}
Let me know if that just horrifies you. It seems when a menu element is created with a browser that supports it, certain attributes are intrinsically defined.

Old JavaScript Function Crashes Browser

I'm integrating a mootools script onto a page which has very old JavaScript functions which run a navigation vertical menu. This old script will be hard to change now.
The line breaking is:
function stgobj(id) {
with(document) return nIE && nVER < 5 ? all[id] : nNN4 ? layers[id] : getElementById(id);
}
Not sure exactly what's it's purpose, but it looks like it's rendering some elements. If commented the menu will disappear.
FF, Chrome, IE(doesn't crash, but menu does not render)
Any quick patch to resolve the browsers crashing?
Looks like its purpose is to return the element corresponding to the given ID. The code simply uses some different methods based on the browser - document.all for IE5 and earlier, and document.layers for Netscape 4. Unless you need to support those ancient browsers, you could alter the function to return just document.getElementById(id). Or better yet, ditch this function altogether and call document.getElementById directly.
However, if it's crashing modern browsers like Firefox and Chrome, then you should also look at the browser detection logic (the code that populates the nIE, nVER and nNN4 variables), otherwise it might just end up crashing elsewhere.
It's a "compatibility" function for document.getElementById. I think you should be able to equal it:
stgobj = document.getElementById.bind(document);

what browser is document.layers sniffing?

I am looking at some JS code from the 20th century, and they are using document.layers in code that is trying to get the current key code. What browser are they sniffing for?
i am about to replace the code with something like this:
var fn = function(event){
event = event || window.event;
var code = event.charCode || event.keyCode;
}
but i am afraid of breaking something arcane and releasing the evil
document.layers exists in Netscape 4 and holds all <layer> and <ilayer> elements.
It was an early precursor to true DHTML.
For more information, see here. (Ten years old)
Netscape 4 is not able to display any modern web-page due to it's total lack of CSS support - so if you drop the support for this browser then you are not breaking anything that isnt already broken.

Categories

Resources