<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Robert Accettura&#039;s Fun With Wordage &#187; prototypejs</title>
	<atom:link href="http://robert.accettura.com/blog/tag/prototypejs/feed/" rel="self" type="application/rss+xml" />
	<link>http://robert.accettura.com</link>
	<description>Robert Accettura&#039;s Personal Blog on Web Development and Tech</description>
	<lastBuildDate>Thu, 09 Feb 2012 01:43:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<atom:link rel='hub' href='http://robert.accettura.com/?pushpress=hub'/>
<cloud domain='robert.accettura.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
		<item>
		<title>Browser Detection In JavaScript Libraries</title>
		<link>http://robert.accettura.com/blog/2009/11/30/browser-detection-in-javascript-libraries/</link>
		<comments>http://robert.accettura.com/blog/2009/11/30/browser-detection-in-javascript-libraries/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 02:00:14 +0000</pubDate>
		<dc:creator>Robert</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[firefox 3.6]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[mootools]]></category>
		<category><![CDATA[prototypejs]]></category>
		<category><![CDATA[yui]]></category>

		<guid isPermaLink="false">http://robert.accettura.com/?p=3084</guid>
		<description><![CDATA[I was curious what browser detection in various JS libraries look like. While we always try to avoid doing browser detection, it&#8217;s sometimes a necessary evil. Here&#8217;s what I found. jQuery jQuery looks something like this in syntax: if($.browser.msie) { &#8230; <a href="http://robert.accettura.com/blog/2009/11/30/browser-detection-in-javascript-libraries/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I was curious what browser detection in various JS libraries look like.  While we always try to avoid doing browser detection, it&#8217;s sometimes a necessary evil.  Here&#8217;s what I found.</p>
<p><span id="more-3084"></span></p>
<h3>jQuery</h3>
<p><a href="http://www.jquery.org">jQuery</a> looks something like this in syntax:</p>
<pre>
if($.browser.msie) {
  // do something IE specific
}
</pre>
<p>Here&#8217;s how it&#8217;s actually <a href="http://github.com/jquery/jquery/blob/master/src/core.js#L506">implemented</a>:</p>
<pre>
browser: {
  version: (/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/.exec(userAgent) || [0,'0'])[1],
  safari: /webkit/.test( userAgent ),
  opera: /opera/.test( userAgent ),
  msie: /msie/.test( userAgent ) &amp;amp;&amp;amp; !/opera/.test( userAgent ),
  mozilla: /mozilla/.test( userAgent ) &amp;amp;&amp;amp; !/(compatible|webkit)/.test( userAgent )
}
</pre>
<p>jQuery takes a pretty simple user-agent parsing approach.  All jQuery supports (though deprecated officially) is the rendering engine, and version.   Noteworthy is that &#8220;<code>safari</code>&#8221; is used as opposed to &#8220;<code>webkit</code>&#8220;.  This is important in the case of Google Chrome etc. which you would detect using the poorly named &#8220;<code>safari</code>&#8220;.  No support for detecting mobile browsers, though that could be added pretty easily.</p>
<p>jQuery is pretty bare bones, but the tightest of the implementations.  It&#8217;s also the only one I&#8217;m aware of that has deprecated this functionality.  The one thing I occasionally miss is OS detection (helpful when Linux lacks a few things like good Flash support).  I supplement it with:</p>
<pre>
var jQbrowser = navigator.userAgent.toLowerCase();
jQuery.os = {
  mac: /mac/.test(jQbrowser),
  win: /win/.test(jQbrowser),
  linux: /linux/.test(jQbrowser)
};
</pre>
<p>Then use it like this:</p>
<pre>
if($.os.linux) {
  // do something for Linux
}
</pre>
<h3>MooTools</h3>
<p><a href="http://mootools.net/">MooTools</a> syntax looks something like this:</p>
<pre>
if(Browser.Engine.trident) {
  // do something IE specific
}
</pre>
<p>It also supports a few other attributes such as <code>Platform</code>, <code>Browser.Features.xpath</code> (XPath supported?) <code>Browser.Features.xhr</code> (xmlHttpRequest supported?), and <code>Browser.Plugins.Flash.version</code> (Flash version).</p>
<p>Here&#8217;s how the core of it is <a href="http://github.com/mootools/mootools-core/blob/master/Source/Core/Browser.js#L29">implemented</a> (I&#8217;m omitting the extras):</p>
<pre>
var Browser = $merge({

  Engine: {name: 'unknown', version: 0},

  Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},

  Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},

  Plugins: {},

  Engines: {

    presto: function(){
      return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
    },

    trident: function(){
      return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
    },

    webkit: function(){
      return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
    },

    gecko: function(){
      return (!document.getBoxObjectFor &amp;amp;&amp;amp; window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18);
    }

  }

}, Browser || {});
</pre>
<p>MooTools choose feature detection rather than User Agent sniffing.   This approach takes care of the problem with spoofed request headers, but is failtastic when using an <a href="http://ejohn.org/blog/the-getboxobjectfor-apocalypse/">unsupported method</a>.  MooTools users need to <a href="http://mootools.net/blog/2009/11/02/upgrade-mootools/">upgrade</a> ASAP.   This will be problematic with the upcoming Firefox 3.6 release.</p>
<h3>Prototype.js</h3>
<p><a href="http://www.prototypejs.org/">Prototype&#8217;s</a> syntax looks something like this:</p>
<pre>
if(Prototype.Browser.IE){
  // do something IE specific
}
</pre>
<p>Here is what the <a href="http://github.com/sstephenson/prototype/blob/master/src/prototype.js#L12">implementation</a> looks like:</p>
<pre>
  Browser: (function(){
    var ua = navigator.userAgent;
    // Opera (at least) 8.x+ has &quot;Opera&quot; as a [[Class]] of `window.opera`
    // This is a safer inference than plain boolean type conversion of `window.opera`
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE: !!window.attachEvent &amp;amp;&amp;amp; !isOpera,
      Opera: isOpera,
      WebKit: ua.indexOf('AppleWebKit/') &amp;gt; -1,
      Gecko: ua.indexOf('Gecko') &amp;gt; -1 &amp;amp;&amp;amp; ua.indexOf('KHTML') === -1,
      MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
    }
  })(),
</pre>
<p>It&#8217;s pretty similar (though not identical) to jQuery with the most notable exception being the addition of MobileSafari and object detection for IE.</p>
<h3>YUI</h3>
<p>The syntax in the <a href="http://developer.yahoo.com/yui/">YUI</a> world is like this:</p>
<pre>
if (Y.UA.ie &amp;gt; 0) {
  // do something IE specific
}
</pre>
<p>The <a href="http://github.com/yui/yui3/blob/master/src/yui/js/yui-ua.js">implementation</a> is the longest I&#8217;ve seen:</p>
<pre>
ua = nav &amp;amp;&amp;amp; nav.userAgent,
if (ua) {

  if ((/windows|win32/i).test(ua)) {
    o.os = 'windows';
  } else if ((/macintosh/i).test(ua)) {
    o.os = 'macintosh';
  }

  // Modern KHTML browsers should qualify as Safari X-Grade
  if ((/KHTML/).test(ua)) {
    o.webkit=1;
  }
  // Modern WebKit browsers are at least X-Grade
  m=ua.match(/AppleWebKit\/([^\s]*)/);
  if (m&amp;amp;&amp;amp;m[1]) {
    o.webkit=numberfy(m[1]);

    // Mobile browser check
    if (/ Mobile\//.test(ua)) {
      o.mobile = &quot;Apple&quot;; // iPhone or iPod Touch
    } else {
      m=ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/);
      if (m) {
        o.mobile = m[0]; // Nokia N-series, Android, webOS, ex: NokiaN95
      }
    }

    m=ua.match(/AdobeAIR\/([^\s]*)/);
    if (m) {
      o.air = m[0]; // Adobe AIR 1.0 or better
    }

  }

  if (!o.webkit) { // not webkit
    // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
    m=ua.match(/Opera[\s\/]([^\s]*)/);
    if (m&amp;amp;&amp;amp;m[1]) {
      o.opera=numberfy(m[1]);
      m=ua.match(/Opera Mini[^;]*/);
      if (m) {
        o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
      }
    } else { // not opera or webkit
      m=ua.match(/MSIE\s([^;]*)/);
      if (m&amp;amp;&amp;amp;m[1]) {
        o.ie=numberfy(m[1]);
      } else { // not opera, webkit, or ie
        m=ua.match(/Gecko\/([^\s]*)/);
        if (m) {
          o.gecko=1; // Gecko detected, look for revision
          m=ua.match(/rv:([^\s\)]*)/);
          if (m&amp;amp;&amp;amp;m[1]) {
            o.gecko=numberfy(m[1]);
          }
        }
      }
    }
  }
}
</pre>
<p>This seems a little excessive, especially for UA parsing, though the detection of <code>AdobeAIR</code> and <code>Opera Mini</code> is a nice touch.  The code being well commented is nice though.</p>
<h3>Conclusion</h3>
<p>So there you have it.  Unlike many of those websites that don&#8217;t use a library, these JS code bases don&#8217;t rely on <code>document.all</code> and/or <code>window.xmlHttpRequest</code><sup>[1]</sup> to do it all.</p>
<p><small id="footnote-1">1.  For those wondering xhr is to tell IE7+ from previous IE versions.</small>
<div id="rja_commentCountImage"><a href="http://robert.accettura.com/?p=3084#comments"><img src="http://robert.accettura.com/wp-content/commentCount/2009/12/1706f19.gif" alt="Comment Count" style="border:0;" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://robert.accettura.com/blog/2009/11/30/browser-detection-in-javascript-libraries/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

