// Copyright 2006 Google Inc.
// All Rights Reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview Rendering engine detection.
* @see User agent strings
* For information on the browser brand (such as Safari versus Chrome), see
* goog.userAgent.product.
*/
goog.provide('goog.userAgent');
goog.require('goog.string');
/**
* @define {boolean} Whether we know at compile-time that the browser is IE.
*/
goog.userAgent.ASSUME_IE = false;
/**
* @define {boolean} Whether we know at compile-time that the browser is GECKO.
*/
goog.userAgent.ASSUME_GECKO = false;
/**
* @define {boolean} Whether we know at compile-time that the browser is CAMINO.
* @deprecated Use goog.userAgent.product.ASSUME_CAMINO instead.
*/
goog.userAgent.ASSUME_CAMINO = false;
/**
* @define {boolean} Whether we know at compile-time that the browser is WEBKIT.
*/
goog.userAgent.ASSUME_WEBKIT = false;
/**
* @define {boolean} Whether we know at compile-time that the browser is a
* mobile device running WebKit e.g. iPhone or Android.
*/
goog.userAgent.ASSUME_MOBILE_WEBKIT = false;
/**
* @define {boolean} Whether we know at compile-time that the browser is OPERA.
*/
goog.userAgent.ASSUME_OPERA = false;
/**
* Whether we know the browser engine at compile-time.
* @type {boolean}
* @private
*/
goog.userAgent.BROWSER_KNOWN_ =
goog.userAgent.ASSUME_IE ||
goog.userAgent.ASSUME_GECKO ||
goog.userAgent.ASSUME_CAMINO ||
goog.userAgent.ASSUME_MOBILE_WEBKIT ||
goog.userAgent.ASSUME_WEBKIT ||
goog.userAgent.ASSUME_OPERA;
/**
* Returns the userAgent string for the current browser.
* Some user agents (I'm thinking of you, Gears WorkerPool) do not expose a
* navigator object off the global scope. In that case we return null.
*
* @return {string?} The userAgent string or null if there is none.
*/
goog.userAgent.getUserAgentString = function() {
return goog.global['navigator'] ? goog.global['navigator'].userAgent : null;
};
/**
* @return {Object} The native navigator object.
*/
goog.userAgent.getNavigator = function() {
// Need a local navigator reference instead of using the global one,
// to avoid the rare case where they reference different objects.
// (goog.gears.FakeWorkerPool, for example).
return goog.global['navigator'];
};
/**
* Initializer for goog.userAgent.
*
* This is a named function so that it can be stripped via the jscompiler
* option for stripping types.
* @private
*/
goog.userAgent.init_ = function() {
/**
* Whether the user agent string denotes Opera.
* @type {boolean}
* @private
*/
goog.userAgent.detectedOpera_ = false;
/**
* Whether the user agent string denotes Internet Explorer. This includes
* other browsers using Trident as its rendering engine. For example AOL
* and Netscape 8
* @type {boolean}
* @private
*/
goog.userAgent.detectedIe_ = false;
/**
* Whether the user agent string denotes WebKit. WebKit is the rendering
* engine that Safari, Android and others use.
* @type {boolean}
* @private
*/
goog.userAgent.detectedWebkit_ = false;
/**
* Whether the user agent string denotes a mobile device.
* @type {boolean}
* @private
*/
goog.userAgent.detectedMobile_ = false;
/**
* Whether the user agent string denotes Gecko. Gecko is the rendering
* engine used by Mozilla, Mozilla Firefox, Camino and many more.
* @type {boolean}
* @private
*/
goog.userAgent.detectedGecko_ = false;
/**
* Whether the user agent is Camino.
* @type {boolean}
*/
goog.userAgent.detectedCamino_ = false;
var ua;
if (!goog.userAgent.BROWSER_KNOWN_ &&
(ua = goog.userAgent.getUserAgentString())) {
var navigator = goog.userAgent.getNavigator();
goog.userAgent.detectedOpera_ = ua.indexOf('Opera') == 0;
goog.userAgent.detectedIe_ = !goog.userAgent.detectedOpera_ &&
ua.indexOf('MSIE') != -1;
goog.userAgent.detectedWebkit_ = !goog.userAgent.detectedOpera_ &&
ua.indexOf('WebKit') != -1;
// WebKit also gives navigator.product string equal to 'Gecko'.
goog.userAgent.detectedMobile_ = goog.userAgent.detectedWebkit_ &&
ua.indexOf('Mobile') != -1;
goog.userAgent.detectedGecko_ = !goog.userAgent.detectedOpera_ &&
!goog.userAgent.detectedWebkit_ && navigator.product == 'Gecko';
goog.userAgent.detectedCamino_ = goog.userAgent.detectedGecko_ &&
navigator.vendor == 'Camino';
}
};
if (!goog.userAgent.BROWSER_KNOWN_) {
goog.userAgent.init_();
}
/**
* Whether the user agent is Opera.
* @type {boolean}
*/
goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ?
goog.userAgent.ASSUME_OPERA : goog.userAgent.detectedOpera_;
/**
* Whether the user agent is Internet Explorer. This includes other browsers
* using Trident as its rendering engine. For example AOL and Netscape 8
* @type {boolean}
*/
goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ?
goog.userAgent.ASSUME_IE : goog.userAgent.detectedIe_;
/**
* Whether the user agent is Gecko. Gecko is the rendering engine used by
* Mozilla, Mozilla Firefox, Camino and many more.
* @type {boolean}
*/
goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ?
goog.userAgent.ASSUME_GECKO || goog.userAgent.ASSUME_CAMINO :
goog.userAgent.detectedGecko_;
/**
* Whether the user agent is Camino.
* @type {boolean}
* @deprecated Use {@link goog.userAgent.product.CAMINO} instead.
*/
goog.userAgent.CAMINO = goog.userAgent.BROWSER_KNOWN_ ?
goog.userAgent.ASSUME_CAMINO : goog.userAgent.detectedCamino_;
/**
* Whether the user agent is WebKit. WebKit is the rendering engine that
* Safari, Android and others use.
* @type {boolean}
*/
goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ?
goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT :
goog.userAgent.detectedWebkit_;
/**
* Whether the user agent is running on a mobile device.
* @type {boolean}
*/
goog.userAgent.MOBILE = goog.userAgent.ASSUME_MOBILE_WEBKIT ||
goog.userAgent.detectedMobile_;
/**
* Used while transitioning code to use WEBKIT instead.
* @type {boolean}
* @deprecated Use {@link goog.userAgent.product.SAFARI} instead.
*/
goog.userAgent.SAFARI = goog.userAgent.WEBKIT;
/**
* @return {string} the platform (operating system) the user agent is running
* on. Default to empty string because navigator.platform may not be defined
* (on Rhino, for example).
* @private
*/
goog.userAgent.determinePlatform_ = function() {
var navigator = goog.userAgent.getNavigator();
return navigator && navigator.platform || '';
};
/**
* The platform (operating system) the user agent is running on. Default to
* empty string because navigator.platform may not be defined (on Rhino, for
* example).
* @type {string}
*/
goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_();
/**
* @define {boolean} Whether the user agent is running on a Macintosh operating
* system.
*/
goog.userAgent.ASSUME_MAC = false;
/**
* @define {boolean} Whether the user agent is running on a Windows operating
* system.
*/
goog.userAgent.ASSUME_WINDOWS = false;
/**
* @define {boolean} Whether the user agent is running on a Linux operating
* system.
*/
goog.userAgent.ASSUME_LINUX = false;
/**
* @type {boolean}
* @private
*/
goog.userAgent.PLATFORM_KNOWN_ =
goog.userAgent.ASSUME_MAC ||
goog.userAgent.ASSUME_WINDOWS ||
goog.userAgent.ASSUME_LINUX;
/**
* Initialize the goog.userAgent constants that define which platform the user
* agent is running on.
* @private
*/
goog.userAgent.initPlatform_ = function() {
/**
* Whether the user agent is running on a Macintosh operating system.
* @type {boolean}
*/
goog.userAgent.detectedMac_ = goog.string.contains(goog.userAgent.PLATFORM,
'Mac');
/**
* Whether the user agent is running on a Windows operating system.
* @type {boolean}
*/
goog.userAgent.detectedWindows_ = goog.string.contains(
goog.userAgent.PLATFORM, 'Win');
/**
* Whether the user agent is running on a Linux operating system.
* @type {boolean}
*/
goog.userAgent.detectedLinux_ = goog.string.contains(goog.userAgent.PLATFORM,
'Linux');
};
if (!goog.userAgent.PLATFORM_KNOWN_) {
goog.userAgent.initPlatform_();
}
/**
* Whether the user agent is running on a Macintosh operating system.
* @type {boolean}
*/
goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ?
goog.userAgent.ASSUME_MAC : goog.userAgent.detectedMac_;
/**
* Whether the user agent is running on a Windows operating system.
* @type {boolean}
*/
goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ?
goog.userAgent.ASSUME_WINDOWS : goog.userAgent.detectedWindows_;
/**
* Whether the user agent is running on a Linux operating system.
* @type {boolean}
*/
goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ?
goog.userAgent.ASSUME_LINUX : goog.userAgent.detectedLinux_;
/**
* @return {string} The string that describes the version number of the user
* agent.
* @private
*/
goog.userAgent.determineVersion_ = function() {
// All browsers have different ways to detect the version and they all have
// different naming schemes.
// version is a string rather than a number because it may contain 'b', 'a',
// and so on.
var version = '', re;
// goog.userAgent.X and goog.userAgent.DETECTED_X_ are both checked so this
// code can be tested in useragent_test.html but also be compiled efficiently
// as verified in CompileUserAgentTest.java.
if (goog.userAgent.OPERA && goog.global['opera']) {
var operaVersion = goog.global['opera'].version;
version = typeof operaVersion == 'function' ? operaVersion() : operaVersion;
} else {
if (goog.userAgent.GECKO) {
re = /rv\:([^\);]+)(\)|;)/;
} else if (goog.userAgent.IE) {
re = /MSIE\s+([^\);]+)(\)|;)/;
} else if (goog.userAgent.WEBKIT) {
// WebKit/125.4
re = /WebKit\/(\S+)/;
}
if (re) {
var arr = re.exec(goog.userAgent.getUserAgentString());
version = arr ? arr[1] : '';
}
}
return version;
};
/**
* The version of the user agent. This is a string because it might contain
* 'b' (as in beta) as well as multiple dots.
* @type {string}
*/
goog.userAgent.VERSION = goog.userAgent.determineVersion_();
/**
* Compares two version numbers.
*
* @param {string} v1 Version of first item.
* @param {string} v2 Version of second item.
*
* @return {Number} 1 if first argument is higher
* 0 if arguments are equal
* -1 if second argument is higher.
* @deprecated Use goog.string.compareVersions.
*/
goog.userAgent.compare = function(v1, v2) {
return goog.string.compareVersions(v1, v2);
};
/**
* Cache for {@link goog.userAgent.isVersion}. Calls to compareVersions are
* surprisingly expensive and as a browsers version number is unlikely to change
* during a session we cache the results.
* @type {Object}
* @private
*/
goog.userAgent.isVersionCache_ = {};
/**
* Whether the user agent version is higher or the same as the given version.
* NOTE: When checking the version numbers for Firefox and Safari, be sure to
* use the engine's version, not the browser's version number. For example,
* Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11.
* Opera and Internet Explorer versions match the product release number.
* @see Webkit
* @see Gecko
*
* @param {string} version The version to check.
* @return {boolean} Whether the user agent version is higher or the same as
* the given version.
*/
goog.userAgent.isVersion = function(version) {
return goog.userAgent.isVersionCache_[version] ||
(goog.userAgent.isVersionCache_[version] =
goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0);
};