diff --git a/package.json b/package.json index 96e0cdc..b676e7b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title" : "UA-Parser.js", "name" : "ua-parser-js", - "version" : "0.1.2", + "version" : "0.3.0", "author" : { "name" : "Faisal Salman", "email" : "fyzlman@gmail.com", @@ -11,7 +11,10 @@ "keywords" : [ "user-agent", "parser", - "browser" + "browser", + "engine", + "os", + "device" ], "homepage" : "http://faisalman.github.com/ua-parser-js", "contributors": [ diff --git a/readme.md b/readme.md index 57fa7a6..b2c4b6a 100644 --- a/readme.md +++ b/readme.md @@ -5,28 +5,32 @@ JavaScript-based user-agent parser * Author : Faisalman <> * Home : http://faisalman.github.com/ua-parser-js * Source : https://github.com/faisalman/ua-parser-js -* License : GPLv2 +* License : GPLv2 & MIT ## Features -Get detailed type and version of web browser, layout engine, and operating system. +Get detailed type and version of web browser, layout engine, operating system, and device. ## Methods * `getBrowser([uastring])` * `getEngine([uastring])` * `getOS([uastring])` +* `getDevice([uastring])` * `setUA(uastring)` +## Properties + +* `result` + ## Example ```html ``` +## Using node.js + +```js +var parser = require('ua-parser'); + +var ua1 = 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11 (KHTML, like Gecko) Version/7.1.0.7 Safari/534.11'; +var ua2 = 'Midori/0.2 (X11; Linux; U; cs-cz) WebKit/531.2+'; + +parser.setUA(ua1).getDevice().name; // prints "PlayBook" +parser.getOS() // prints {name: "RIM Tablet OS", version: "1.0.0"} +parser.getOS(ua2) // prints {name: "Linux", version: undefined} +parser.getOS() // prints {name: "RIM Tablet OS", version: "1.0.0"} +parser.getEngine().name; // prints "AppleWebKit" +``` + ## License Copyright © 2012 Faisalman <> diff --git a/ua-parser.js b/ua-parser.js index 142e85b..5680caf 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,216 +1,231 @@ -// UA-Parser.js v0.2.0 +// UA-Parser.js v0.3.0 // Lightweight JavaScript-based user-agent parser // https://github.com/faisalman/ua-parser-js // // Copyright © 2012 Faisalman -// Licensed under GPLv2 +// Licensed under GPLv2 & MIT -function UAParser (uastring) { +(function () { + function UAParser (uastring) { - var ua = uastring || window.navigator.userAgent; + var ua = uastring || typeof window !== 'undefined' ? window.navigator.userAgent : ""; - // regexp mapper - var regxMap = function (ua) { - var result; - var i, j, k, l; - for (i = 1; i < arguments.length; i += 2) { - var regex = arguments[i]; - var props = arguments[i + 1]; - var isMatchFound = false; - for (j = 0; j < regex.length; j++) { - var match = regex[j].exec(ua); - //console.log(match); - if (!!match) { + // regexp mapper + var regxMap = function (ua) { + var result; + var i, j, k, l; + for (i = 1; i < arguments.length; i += 2) { + var regex = arguments[i]; + var props = arguments[i + 1]; + var isMatchFound = false; + for (j = 0; j < regex.length; j++) { + var match = regex[j].exec(ua); + //console.log(match); + if (!!match) { + result = {}; + l = 1; + for (k = 0; k < props.length; k++) { + if (typeof props[k] === 'object' && props[k].length === 2) { + result[props[k][0]] = props[k][1]; + l -= 1; + } else if (typeof props[k] === 'object' && props[k].length === 3) { + result[props[k][0]] = (!!match[k + l]) ? match[k + l].replace(props[k][1], props[k][2]) : undefined; + } else { + result[props[k]] = (!!match[k + l]) ? match[k + l] : undefined; + } + } + isMatchFound = true; + break; + } + } + if (!isMatchFound) { result = {}; - l = 1; - for (k = 0; k < props.length; k++) { - if (typeof props[k] === 'object' && props[k].length === 2) { - result[props[k][0]] = props[k][1]; - l -= 1; - } else if (typeof props[k] === 'object' && props[k].length === 3) { - result[props[k][0]] = (!!match[k + l]) ? match[k + l].replace(props[k][1], props[k][2]) : undefined; - } else { - result[props[k]] = (!!match[k + l]) ? match[k + l] : undefined; + for (k in props) { + if (props.hasOwnProperty(k)) { + if (typeof props[k] == 'object') { + result[props[k][0]] = undefined; + } else { + result[props[k]] = undefined; + } } } - isMatchFound = true; - break; + } else { + return result; } } - if (!isMatchFound) { - result = {}; - for (k in props) { - if (props.hasOwnProperty(k)) { - if (typeof props[k] == 'object') { - result[props[k][0]] = undefined; - } else { - result[props[k]] = undefined; - } - } - } - } else { - return result; - } - } - return result; - }; - - var mapper = { - os : { - win: function (str, match) { - switch (match.toLowerCase()) { - case 'nt 5.0': - return '2000'; - case 'nt 5.1': - case 'nt 5.2': - return 'XP'; - case 'nt 6.0': - return 'Vista'; - case 'nt 6.1': - return '7'; - case 'nt 6.2': - return '8'; - default: - return match; - }; - } - } - }; - - this.getBrowser = function (uastring) { - - return regxMap(uastring || ua, [ - - // Mixed - /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine)[\/\s]?((\d+)?[\w\.]+)/i, // Lunascape/Maxthon/Netfront/Jasmine - - // Presto based - /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini - /(opera\smobi)\/((\d+)?[\w\.-]+)/i, // Opera Mobile - /(opera).*\/((\d+)?[\w\.]+)/i, // Opera - - // Trident based - /(avant\sbrowser|iemobile|slimbrowser)[\/\s]?((\d+)?[\w\.]*)/i, // Avant/IEMobile/SlimBrowser - /ms(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer - - // Webkit/KHTML based - /(chromium|flock|rockmelt|midori|epiphany)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany - /(chrome|omniweb|arora|dolfin)\/((\d+)?[\w\.]+)/i, // Chrome/OmniWeb/Arora/Dolphin - ], ['name', 'version', 'major'], [ - /android.+crmo\/((\d+)?[\w\.]+)/i, // Chrome for Android - ], [['name', 'Chrome'], 'version', 'major'], [ - /(mobile\ssafari|safari|konqueror)\/((\d+)?[\w\.]+)/i, // Safari/Konqueror - /(applewebkit|khtml)\/((\d+)?[\w\.]+)/i, - - // Gecko based - /(iceweasel|camino|fennec|maemo|minimo)[\/\s]?((\d+)?[\w\.\+]+)/i, // Iceweasel/Camino/Fennec/Maemo/Minimo - /(firefox|seamonkey|netscape|navigator|k-meleon|icecat|iceape)\/((\d+)?[\w\.]+)/i, - // Firefox/SeaMonkey/Netscape/K-Meleon/IceCat/IceApe - /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla - - // Other - /(lynx|dillo|icab)[\/\s]?((\d+)?[\w\.]+)/i, // Lynx/Dillo/iCab - ], ['name', 'version', 'major']); - }; - - this.getEngine = function (uastring) { - - return regxMap(uastring || ua, [ - - /(presto)\/([\w\.]+)/i, // Presto - /([aple]*webkit|trident)\/([\w\.]+)/i, // Webkit/Trident - /(khtml)\/([\w\.]+)/i // KHTML - ], ['name', 'version'], [ - - /rv\:([\w\.]+).*(gecko)/i // Gecko - ], ['version', 'name']); - }; - - this.getOS = function (uastring) { - - return regxMap(uastring || ua, [ - - // Windows based - /(windows\sphone\sos|windows)\s+([\w\.\s]+)*/i, // Windows - ], ['name', ['version', /(nt\s[\d\.]+)/gi, mapper.os.win]], [ - - // Mobile/Embedded OS - /(blackberry).+version\/([\w\.]+)/i, // Blackberry - /(android|symbianos|symbos|webos|palm\os|qnx|bada|rim\stablet\sos)[\/\s-]?([\w\.]+)*/i, - // Android/Symbian/WebOS/Palm/QNX/Bada/RIM - /(nintendo|playstation)\s([wids3portable]+)/i, // Nintendo/Playstation - - // GNU/Linux based - /(mint)[\/\s\(]?(\w+)*/i, // Mint - /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, - // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware - // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk - /(gnu|linux)\s?([\w\.]+)*/i // Other GNU/Linux - ], ['name', 'version'], [ - - /cros\s([\w\.\s]+)/i // Chromium OS - ], [['name', 'Chromium OS'], 'version'],[ - - // Solaris - /sunos\s?([\w\.\s]+)*/i // Solaris - ], [['name', 'Solaris'], 'version'], [ - - // BSD based - /\s(\w*bsd|dragonfly)\s?([\w\.]+)*/i, // FreeBSD/NetBSD/OpenBSD/DragonFly - ], ['name', 'version'],[ - - /(ip[honead]+).*os\s*([\w]+)*\slike\smac/i // iOS - ], [['name', /.+/g, 'iOS'], ['version', /_/g, '.']], [ - - /(mac\sos)\sx\s([\w\s\.]+)/i, // Mac OS - ], ['name', ['version', /_/g, '.']], [ - - // Other - /(macintosh|unix|minix|beos)[\/\s]?()*/i - ], ['name', 'version']); - }; - - this.getDevice = function (uastring) { - - return regxMap(uastring || ua, [ - - /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook - /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|nokia|palm(?=\-)|sonyericsson)[\s-]?([\w-]+)*/i, // BenQ/Nokia/Palm/Sony-Ericsson - /(hp)\s([\w\s]+)/i, // HP iPAQ - /(hp).+(touchpad)/i, // HP TouchPad - /(kindle)\/([\w\.]+)/i, // Kindle - /(lg)[e;\s-]+(\w+)*/i, // LG - /(nintendo|playstation)\s([wids3portable]+)/i // Nintendo/Playstation - ], ['name', 'version'], [ - - /(htc)[;_\s-]+([\w\s]+(?=\))|[\w]+)*/i, // HTC - /(zte)-([\w]+)*/i - ], ['name', ['version', /_/g, ' ']], [ - - /\s(milestone|mz601|droid[2x]?|xoom)[globa\s]*\sbuild\//i, // Motorola - /mot[\s-]?(\w+)*/i - ], [['name', 'Motorola'], 'version'], [ - - /(s[cgp]h-\w+|gt-\w+|galaxy\snexus)/i, // Samsung - /sam[sung]*[\s-]*(\w+-?[\w-]*)*/i, - /sec-(sgh\w+)/i - ], [['name', 'Samsung'], 'version'], [ - - /sie-(\w+)*/i // Siemens - ], [['name', 'Siemens'], 'version']); - }; - - this.setUA = function (uastring) { - ua = uastring || ua; - return this.result = { - browser : this.getBrowser(), - engine : this.getEngine(), - os : this.getOS(), - device : this.getDevice() + return result; }; - }; - this.setUA(ua); -}; + var mapper = { + os : { + win: function (str, match) { + switch (match.toLowerCase()) { + case 'nt 5.0': + return '2000'; + case 'nt 5.1': + case 'nt 5.2': + return 'XP'; + case 'nt 6.0': + return 'Vista'; + case 'nt 6.1': + return '7'; + case 'nt 6.2': + return '8'; + default: + return match; + }; + } + } + }; + + this.getBrowser = function (uastring) { + + return regxMap(uastring || ua, [ + + // Mixed + /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle + /(lunascape|maxthon|netfront|jasmine)[\/\s]?((\d+)?[\w\.]+)/i, // Lunascape/Maxthon/Netfront/Jasmine + + // Presto based + /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini + /(opera\smobi)\/((\d+)?[\w\.-]+)/i, // Opera Mobile + /(opera).*\/((\d+)?[\w\.]+)/i, // Opera + + // Trident based + /(avant\sbrowser|iemobile|slimbrowser)[\/\s]?((\d+)?[\w\.]*)/i, // Avant/IEMobile/SlimBrowser + /ms(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer + + // Webkit/KHTML based + /(chromium|flock|rockmelt|midori|epiphany)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany + /(chrome|omniweb|arora|dolfin)\/((\d+)?[\w\.]+)/i, // Chrome/OmniWeb/Arora/Dolphin + ], ['name', 'version', 'major'], [ + /android.+crmo\/((\d+)?[\w\.]+)/i, // Chrome for Android + ], [['name', 'Chrome'], 'version', 'major'], [ + /(mobile\ssafari|safari|konqueror)\/((\d+)?[\w\.]+)/i, // Safari/Konqueror + /(applewebkit|khtml)\/((\d+)?[\w\.]+)/i, + + // Gecko based + /(iceweasel|camino|fennec|maemo|minimo)[\/\s]?((\d+)?[\w\.\+]+)/i, // Iceweasel/Camino/Fennec/Maemo/Minimo + /(firefox|seamonkey|netscape|navigator|k-meleon|icecat|iceape)\/((\d+)?[\w\.]+)/i, + // Firefox/SeaMonkey/Netscape/K-Meleon/IceCat/IceApe + /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla + + // Other + /(lynx|dillo|icab)[\/\s]?((\d+)?[\w\.]+)/i, // Lynx/Dillo/iCab + ], ['name', 'version', 'major']); + }; + + this.getEngine = function (uastring) { + + return regxMap(uastring || ua, [ + + /(presto)\/([\w\.]+)/i, // Presto + /([aple]*webkit|trident)\/([\w\.]+)/i, // Webkit/Trident + /(khtml)\/([\w\.]+)/i // KHTML + ], ['name', 'version'], [ + + /rv\:([\w\.]+).*(gecko)/i // Gecko + ], ['version', 'name']); + }; + + this.getOS = function (uastring) { + + return regxMap(uastring || ua, [ + + // Windows based + /(windows\sphone\sos|windows)\s+([\w\.\s]+)*/i, // Windows + ], ['name', ['version', /(nt\s[\d\.]+)/gi, mapper.os.win]], [ + + // Mobile/Embedded OS + /(blackberry).+version\/([\w\.]+)/i, // Blackberry + /(android|symbianos|symbos|webos|palm\os|qnx|bada|rim\stablet\sos)[\/\s-]?([\w\.]+)*/i, + // Android/Symbian/WebOS/Palm/QNX/Bada/RIM + /(nintendo|playstation)\s([wids3portable]+)/i, // Nintendo/Playstation + + // GNU/Linux based + /(mint)[\/\s\(]?(\w+)*/i, // Mint + /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, + // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware + // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk + /(gnu|linux)\s?([\w\.]+)*/i // Other GNU/Linux + ], ['name', 'version'], [ + + /cros\s([\w\.\s]+)/i // Chromium OS + ], [['name', 'Chromium OS'], 'version'],[ + + // Solaris + /sunos\s?([\w\.\s]+)*/i // Solaris + ], [['name', 'Solaris'], 'version'], [ + + // BSD based + /\s(\w*bsd|dragonfly)\s?([\w\.]+)*/i, // FreeBSD/NetBSD/OpenBSD/DragonFly + ], ['name', 'version'],[ + + /(ip[honead]+).*os\s*([\w]+)*\slike\smac/i // iOS + ], [['name', /.+/g, 'iOS'], ['version', /_/g, '.']], [ + + /(mac\sos)\sx\s([\w\s\.]+)/i, // Mac OS + ], ['name', ['version', /_/g, '.']], [ + + // Other + /(macintosh|unix|minix|beos)[\/\s]?()*/i + ], ['name', 'version']); + }; + + this.getDevice = function (uastring) { + + return regxMap(uastring || ua, [ + + /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook + /(blackberry)[\s-]?(\w+)/i, // BlackBerry + /(blackberry|benq|nokia|palm(?=\-)|sonyericsson)[\s-]?([\w-]+)*/i, // BenQ/Nokia/Palm/Sony-Ericsson + /(hp)\s([\w\s]+)/i, // HP iPAQ + /(hp).+(touchpad)/i, // HP TouchPad + /(kindle)\/([\w\.]+)/i, // Kindle + /(lg)[e;\s-]+(\w+)*/i, // LG + /(nintendo|playstation)\s([wids3portable]+)/i // Nintendo/Playstation + ], ['name', 'version'], [ + + /(htc)[;_\s-]+([\w\s]+(?=\))|[\w]+)*/i, // HTC + /(zte)-([\w]+)*/i + ], ['name', ['version', /_/g, ' ']], [ + + /\s(milestone|mz601|droid[2x]?|xoom)[globa\s]*\sbuild\//i, // Motorola + /mot[\s-]?(\w+)*/i + ], [['name', 'Motorola'], 'version'], [ + + /(s[cgp]h-\w+|gt-\w+|galaxy\snexus)/i, // Samsung + /sam[sung]*[\s-]*(\w+-?[\w-]*)*/i, + /sec-(sgh\w+)/i + ], [['name', 'Samsung'], 'version'], [ + + /sie-(\w+)*/i // Siemens + ], [['name', 'Siemens'], 'version']); + }; + + this.setUA = function (uastring) { + ua = uastring || ua; + this.result = { + browser : this.getBrowser(), + engine : this.getEngine(), + os : this.getOS(), + device : this.getDevice() + }; + return this; + }; + + this.setUA(ua); + }; + + var parser = new UAParser(); + + // check whether script is running inside node.js export as module + if (typeof exports !== 'undefined' && this.toString() !== '[object DOMWindow]') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = parser; + } + exports.UAParser = parser; + } else { + this['UAParser'] = parser; + } +})();