From 71b5300080dd0d07040446e768a4ade896b6f125 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 01:05:15 +0700 Subject: [PATCH 01/13] Replace UAParser.result object with UAParser.getResult() --- readme.md | 13 +++++-------- ua-parser.js | 9 ++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index af75017..feb7777 100644 --- a/readme.md +++ b/readme.md @@ -17,13 +17,10 @@ Extract detailed type of web browser, layout engine, operating system, and devic * `getDevice()` * `getEngine()` * `getOS()` +* `getResult()` * `getUA()` * `setUA(uastring)` -## Properties - -* `result` - ## Example ```html @@ -33,7 +30,7 @@ Extract detailed type of web browser, layout engine, operating system, and devic var parser = new UAParser(); // by default it takes ua string from current browser's window.navigator.userAgent - console.log(parser.result); + console.log(parser.getResult()); /* /// this will print an object structured like this: { @@ -61,9 +58,9 @@ Extract detailed type of web browser, layout engine, operating system, and devic var uastr = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.2 (KHTML, like Gecko) Ubuntu/11.10 Chromium/15.0.874.106 Chrome/15.0.874.106 Safari/535.2"; parser.setUA(uastr); - console.log(parser.result.browser); // {name: "Chromium", major: "15", version: "15.0.874.106"} - console.log(parser.result.engine); // {name: "AppleWebKit", version: "535.2"} - console.log(parser.result.os); // {name: "Ubuntu", version: "11.10"} + console.log(parser.getResult().browser); // {name: "Chromium", major: "15", version: "15.0.874.106"} + console.log(parser.getResult().engine); // {name: "AppleWebKit", version: "535.2"} + console.log(parser.getResult().os); // {name: "Ubuntu", version: "11.10"} // let's take another test please console.log(parser.setUA("Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)").getOS().name); // "OpenBSD" diff --git a/ua-parser.js b/ua-parser.js index d5145e8..d20f53a 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -232,14 +232,17 @@ return ua; }; - this.setUA = function (uastring) { - ua = uastring; - this.result = { + this.getResult = function() { + return { browser : this.getBrowser(), engine : this.getEngine(), os : this.getOS(), device : this.getDevice() }; + }; + + this.setUA = function (uastring) { + ua = uastring; return this; }; From 064d52255fb4941ae6a66a9555133d9d169b2172 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 01:15:02 +0700 Subject: [PATCH 02/13] Remove optional argument from all getters --- ua-parser.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ua-parser.js b/ua-parser.js index d20f53a..35b44aa 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -11,15 +11,15 @@ var ua = uastring || (typeof window !== 'undefined' ? window.navigator.userAgent : ""); // regexp mapper - var regxMap = function (ua) { + var regxMap = function (args) { var result = {}, i, j, k, l, m; // loop through all regexes maps - for (i = 1; i < arguments.length; i += 2) { + for (i = 0; i < arguments.length; i += 2) { - var regex = arguments[i], // odd sequence (2,4,6,..) - props = arguments[i + 1]; // even sequence (3,5,7,..) + var regex = arguments[i], // odd sequence (0,2,4,..) + props = arguments[i + 1]; // even sequence (1,3,5,..) // build object barebones for (k = 0; k < props.length; k++) { @@ -88,9 +88,9 @@ } }; - this.getBrowser = function (uastring) { + this.getBrowser = function () { - return regxMap(uastring || ua, [ + return regxMap([ // Mixed /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle @@ -128,9 +128,9 @@ ], ['name', 'version', 'major']); }; - this.getEngine = function (uastring) { + this.getEngine = function () { - return regxMap(uastring || ua, [ + return regxMap([ /(presto)\/([\w\.]+)/i, // Presto /([aple]*webkit|trident)\/([\w\.]+)/i, // Webkit/Trident @@ -141,9 +141,9 @@ ], ['version', 'name']); }; - this.getOS = function (uastring) { + this.getOS = function () { - return regxMap(uastring || ua, [ + return regxMap([ // Windows based /(windows\sphone\sos|windows)\s?([nt\d\.\s]+\d)/i // Windows @@ -189,9 +189,9 @@ ], ['name', 'version']); }; - this.getDevice = function (uastring) { + this.getDevice = function () { - return regxMap(uastring || ua, [ + return regxMap([ /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook /(blackberry)[\s-]?(\w+)/i, // BlackBerry From 65703e7c1a8fb8ea5d0185c6ea55d5217a23ee58 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 01:26:50 +0700 Subject: [PATCH 03/13] Move regexMapper & maps outside UAParser class --- package.json | 2 +- ua-parser.js | 178 +++++++++++++++++++++++++-------------------------- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/package.json b/package.json index f84efb9..11ffd17 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.3.3", + "version": "0.3.4", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/ua-parser.js b/ua-parser.js index 35b44aa..c1e7360 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.3.3 +// UA-Parser.JS v0.3.4 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -6,91 +6,91 @@ // Dual licensed under GPLv2 & MIT (function (undefined) { - var parser = function UAParser (uastring) { + + var regexMapper = function (ua, args) { + + var result = {}, i, j, k, l, m; + + // loop through all regexes maps + for (i = 1; i < arguments.length; i += 2) { + + var regex = arguments[i], // even sequence (1,3,5,..) + props = arguments[i + 1]; // odd sequence (2,4,6,..) + + // build object barebones + for (k = 0; k < props.length; k++) { + if (typeof props[k] == 'object') { + result[props[k][0]] = undefined; + } else { + result[props[k]] = undefined; + } + } + + // try matching uastring with regexes + for (j = 0; j < regex.length; j++) { + l = regex[j].exec(ua); + if (!!l) { + for (k = 0; k < props.length; k++) { + m = l[k + 1]; + if (typeof props[k] === 'object' && props[k].length === 2) { + result[props[k][0]] = props[k][1]; + } else if (typeof props[k] === 'object' && props[k].length === 3) { + result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; + } else { + result[props[k]] = m ? m : undefined; + } + } + break; + } + } + + if(!!l) break; // break the loop immediately if match found + } + return result; + }; + + var maps = { + + check : function(str, map){ + for (var i in map){ + if (map.hasOwnProperty(i)) { + if (typeof map[i] === 'object' && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (str.toLowerCase().indexOf(map[i][j]) !== -1) { + return i; + } + } + } else if (str.toLowerCase().indexOf(map[i]) !== -1) { + return i; + } + } + } + return str; + }, + + os : { + win : function (match, str1) { + return maps.check(str1, { + 'ME' : '4.90', + 'NT 3.11' : 'nt3.51', + 'NT 4.0' : 'nt4.0', + '2000' : 'nt 5.0', + 'XP' : ['nt 5.1', 'nt 5.2'], + 'Vista' : 'nt 6.0', + '7' : 'nt 6.1', + '8' : 'nt 6.2' + }); + } + } + }; + + var UAParser = function UAParser (uastring) { var ua = uastring || (typeof window !== 'undefined' ? window.navigator.userAgent : ""); - // regexp mapper - var regxMap = function (args) { - - var result = {}, i, j, k, l, m; - - // loop through all regexes maps - for (i = 0; i < arguments.length; i += 2) { - - var regex = arguments[i], // odd sequence (0,2,4,..) - props = arguments[i + 1]; // even sequence (1,3,5,..) - - // build object barebones - for (k = 0; k < props.length; k++) { - if (typeof props[k] == 'object') { - result[props[k][0]] = undefined; - } else { - result[props[k]] = undefined; - } - } - - // try matching uastring with regexes - for (j = 0; j < regex.length; j++) { - l = regex[j].exec(ua); - if (!!l) { - for (k = 0; k < props.length; k++) { - m = l[k + 1]; - if (typeof props[k] === 'object' && props[k].length === 2) { - result[props[k][0]] = props[k][1]; - } else if (typeof props[k] === 'object' && props[k].length === 3) { - result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; - } else { - result[props[k]] = m ? m : undefined; - } - } - break; - } - } - - if(!!l) break; // break the loop immediately if match found - } - return result; - }; - - var mapper = { - - check : function(str, map){ - for (var i in map){ - if (map.hasOwnProperty(i)) { - if (typeof map[i] === 'object' && map[i].length > 0) { - for (var j = 0; j < map[i].length; j++) { - if (str.toLowerCase().indexOf(map[i][j]) !== -1) { - return i; - } - } - } else if (str.toLowerCase().indexOf(map[i]) !== -1) { - return i; - } - } - } - return str; - }, - - os : { - win : function (match, str1) { - return mapper.check(str1, { - 'ME' : '4.90', - 'NT 3.11' : 'nt3.51', - 'NT 4.0' : 'nt4.0', - '2000' : 'nt 5.0', - 'XP' : ['nt 5.1', 'nt 5.2'], - 'Vista' : 'nt 6.0', - '7' : 'nt 6.1', - '8' : 'nt 6.2' - }); - } - } - }; - this.getBrowser = function () { - return regxMap([ + return regexMapper(ua, [ // Mixed /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle @@ -130,7 +130,7 @@ this.getEngine = function () { - return regxMap([ + return regexMapper(ua, [ /(presto)\/([\w\.]+)/i, // Presto /([aple]*webkit|trident)\/([\w\.]+)/i, // Webkit/Trident @@ -143,13 +143,13 @@ this.getOS = function () { - return regxMap([ + return regexMapper(ua, [ // Windows based /(windows\sphone\sos|windows)\s?([nt\d\.\s]+\d)/i // Windows - ], ['name', ['version', /(.+)/gi, mapper.os.win]], [ + ], ['name', ['version', /(.+)/gi, maps.os.win]], [ /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i - ], [['name', 'Windows'], ['version', /(.+)/gi, mapper.os.win]], [ + ], [['name', 'Windows'], ['version', /(.+)/gi, maps.os.win]], [ // Mobile/Embedded OS /(blackberry).+version\/([\w\.]+)/i, // Blackberry @@ -191,7 +191,7 @@ this.getDevice = function () { - return regxMap([ + return regexMapper(ua, [ /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook /(blackberry)[\s-]?(\w+)/i, // BlackBerry @@ -252,10 +252,10 @@ // 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 = module.exports = UAParser; } - exports.UAParser = parser; + exports.UAParser = UAParser; } else { - this['UAParser'] = parser; + this['UAParser'] = UAParser; } })(); From ec40433c5c60ca1d95d5cc9009187479c271a695 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 01:47:04 +0700 Subject: [PATCH 04/13] Fix node.js old example in readme --- readme.md | 15 ++++++--------- ua-parser.js | 6 +++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index feb7777..53ccb77 100644 --- a/readme.md +++ b/readme.md @@ -70,16 +70,13 @@ Extract detailed type of web browser, layout engine, operating system, and devic ## Using node.js ```js -var UAParser = require('ua-parser'); -var parser = new UAParser(); -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+'; +var UAParser = require('ua-parser'); +var parser = new UAParser(); +var uaString = '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'; -console.log(parser.setUA(ua1).getDevice().name); // "PlayBook" -console.log(parser.getOS()) // {name: "RIM Tablet OS", version: "1.0.0"} -console.log(parser.getOS(ua2)) // {name: "Linux", version: undefined} -console.log(parser.getOS()) // {name: "RIM Tablet OS", version: "1.0.0"} -console.log(parser.getEngine().name); // "AppleWebKit" +console.log(parser.setUA(uaString).getDevice().name); // "PlayBook" +console.log(parser.getOS()) // {name: "RIM Tablet OS", version: "1.0.0"} +console.log(parser.getEngine().name); // "AppleWebKit" ``` ## License diff --git a/ua-parser.js b/ua-parser.js index c1e7360..0c8a980 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -19,7 +19,7 @@ // build object barebones for (k = 0; k < props.length; k++) { - if (typeof props[k] == 'object') { + if (typeof props[k] === 'object') { result[props[k][0]] = undefined; } else { result[props[k]] = undefined; @@ -51,8 +51,8 @@ var maps = { - check : function(str, map){ - for (var i in map){ + check : function (str, map) { + for (var i in map) { if (map.hasOwnProperty(i)) { if (typeof map[i] === 'object' && map[i].length > 0) { for (var j = 0; j < map[i].length; j++) { From 51822ad1722b7a3bbc455c0044faae8ae82857be Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 02:16:02 +0700 Subject: [PATCH 05/13] Make sure the result only get constructed once --- package.json | 2 +- ua-parser.js | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 11ffd17..1b4482d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.3.4", + "version": "0.3.5", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/ua-parser.js b/ua-parser.js index 0c8a980..bc84ebf 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.3.4 +// UA-Parser.JS v0.3.5 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -9,7 +9,7 @@ var regexMapper = function (ua, args) { - var result = {}, i, j, k, l, m; + var result, i, j, k, l, m; // loop through all regexes maps for (i = 1; i < arguments.length; i += 2) { @@ -18,11 +18,17 @@ props = arguments[i + 1]; // odd sequence (2,4,6,..) // build object barebones - for (k = 0; k < props.length; k++) { - if (typeof props[k] === 'object') { - result[props[k][0]] = undefined; - } else { - result[props[k]] = undefined; + if (typeof result === 'undefined') { + result = {}; + for (k = 0; k < props.length; k++) { + if (typeof props[k] === 'object') { + result[props[k][0]] = undefined; + } else { + result[props[k]] = undefined; + } + } + if (ua.toString() === '') { + return result; } } @@ -217,7 +223,7 @@ /sec-((sgh\w+))/i ], [['name', 'Samsung'], 'version'], [ - /((transfo[prime\s]{4,10}\s\w+|(?:android.*)eeepc))/i // Asus + /((transfo[prime\s]{4,10}\s\w+))|(?:android.*)((eeepc))/i // Asus ], [['name', 'Asus'], 'version'], [ /(sie)-(\w+)*/i // Siemens From 33e6fe42d16c216c54de9aacd13b25d420ef1324 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 02:27:54 +0700 Subject: [PATCH 06/13] Move string checker to outside as strMapper --- ua-parser.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/ua-parser.js b/ua-parser.js index bc84ebf..5f88aa2 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -17,7 +17,7 @@ var regex = arguments[i], // even sequence (1,3,5,..) props = arguments[i + 1]; // odd sequence (2,4,6,..) - // build object barebones + // construct object barebones if (typeof result === 'undefined') { result = {}; for (k = 0; k < props.length; k++) { @@ -54,29 +54,28 @@ } return result; }; - - var maps = { - check : function (str, map) { - for (var i in map) { - if (map.hasOwnProperty(i)) { - if (typeof map[i] === 'object' && map[i].length > 0) { - for (var j = 0; j < map[i].length; j++) { - if (str.toLowerCase().indexOf(map[i][j]) !== -1) { - return i; - } + var strMapper = function (str, map) { + for (var i in map) { + if (map.hasOwnProperty(i)) { + if (typeof map[i] === 'object' && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (str.toLowerCase().indexOf(map[i][j]) !== -1) { + return i; } - } else if (str.toLowerCase().indexOf(map[i]) !== -1) { - return i; } + } else if (str.toLowerCase().indexOf(map[i]) !== -1) { + return i; } } - return str; - }, - + } + return str; + }; + + var maps = { os : { win : function (match, str1) { - return maps.check(str1, { + return strMapper(str1, { 'ME' : '4.90', 'NT 3.11' : 'nt3.51', 'NT 4.0' : 'nt4.0', From 68d124c59c8fd549412ef6df8934eb4cb11f3c07 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 03:48:30 +0700 Subject: [PATCH 07/13] Reorganize the structure of the code --- package.json | 2 +- ua-parser.js | 427 ++++++++++++++++++++++++++------------------------- 2 files changed, 223 insertions(+), 206 deletions(-) diff --git a/package.json b/package.json index 1b4482d..9f5e7eb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.3.5", + "version": "0.4.0", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/ua-parser.js b/ua-parser.js index 5f88aa2..29783c9 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.3.5 +// UA-Parser.JS v0.4.0 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -7,234 +7,247 @@ (function (undefined) { - var regexMapper = function (ua, args) { - - var result, i, j, k, l, m; - - // loop through all regexes maps - for (i = 1; i < arguments.length; i += 2) { - - var regex = arguments[i], // even sequence (1,3,5,..) - props = arguments[i + 1]; // odd sequence (2,4,6,..) - - // construct object barebones - if (typeof result === 'undefined') { - result = {}; - for (k = 0; k < props.length; k++) { - if (typeof props[k] === 'object') { - result[props[k][0]] = undefined; - } else { - result[props[k]] = undefined; - } - } - if (ua.toString() === '') { - return result; - } - } - - // try matching uastring with regexes - for (j = 0; j < regex.length; j++) { - l = regex[j].exec(ua); - if (!!l) { - for (k = 0; k < props.length; k++) { - m = l[k + 1]; - if (typeof props[k] === 'object' && props[k].length === 2) { - result[props[k][0]] = props[k][1]; - } else if (typeof props[k] === 'object' && props[k].length === 3) { - result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; - } else { - result[props[k]] = m ? m : undefined; - } - } - break; - } - } - - if(!!l) break; // break the loop immediately if match found - } - return result; - }; + var mapper = { - var strMapper = function (str, map) { - for (var i in map) { - if (map.hasOwnProperty(i)) { - if (typeof map[i] === 'object' && map[i].length > 0) { - for (var j = 0; j < map[i].length; j++) { - if (str.toLowerCase().indexOf(map[i][j]) !== -1) { - return i; + regex : function () { + + var result, i, j, k, l, m, args = arguments; + + // loop through all regexes maps + for (i = 0; i < args.length; i += 2) { + + var regex = args[i], // odd sequence (0,2,4,..) + props = args[i + 1]; // even sequence (1,3,5,..) + + // construct object barebones + if (typeof result === 'undefined') { + result = {}; + for (k = 0; k < props.length; k++) { + if (typeof props[k] === 'object') { + result[props[k][0]] = undefined; + } else { + result[props[k]] = undefined; } } - } else if (str.toLowerCase().indexOf(map[i]) !== -1) { - return i; + if (this.getUA().toString() === '') { + return result; + } + } + + // try matching uastring with regexes + for (j = 0; j < regex.length; j++) { + l = regex[j].exec(this.getUA()); + if (!!l) { + for (k = 0; k < props.length; k++) { + m = l[k + 1]; + if (typeof props[k] === 'object' && props[k].length === 2) { + result[props[k][0]] = props[k][1]; + } else if (typeof props[k] === 'object' && props[k].length === 3) { + result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; + } else { + result[props[k]] = m ? m : undefined; + } + } + break; + } + } + + if(!!l) break; // break the loop immediately if match found + } + return result; + }, + + string : function (str, map) { + + for (var i in map) { + if (map.hasOwnProperty(i)) { + if (typeof map[i] === 'object' && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (str.toLowerCase().indexOf(map[i][j]) !== -1) { + return i; + } + } + } else if (str.toLowerCase().indexOf(map[i]) !== -1) { + return i; + } } } + return str; } - return str; }; - var maps = { + var maps = { os : { - win : function (match, str1) { - return strMapper(str1, { - 'ME' : '4.90', - 'NT 3.11' : 'nt3.51', - 'NT 4.0' : 'nt4.0', - '2000' : 'nt 5.0', - 'XP' : ['nt 5.1', 'nt 5.2'], - 'Vista' : 'nt 6.0', - '7' : 'nt 6.1', - '8' : 'nt 6.2' - }); + windows : { + version : function (match, str1) { + return mapper.string(str1, { + 'ME' : '4.90', + 'NT 3.11' : 'nt3.51', + 'NT 4.0' : 'nt4.0', + '2000' : 'nt 5.0', + 'XP' : ['nt 5.1', 'nt 5.2'], + 'Vista' : 'nt 6.0', + '7' : 'nt 6.1', + '8' : 'nt 6.2' + }); + } } } }; + + var regexes = { + + browser : [[ + + // 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).+version\/((\d+)?[\w\.]+)/i, // Opera + /(opera)[\/\s]+((\d+)?[\w\.]+)/i, + + // 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|silk)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany + /(chrome|omniweb|arora|dolfin|[tizenaok]{5}\s?browser)\/((\d+)?[\w\.]+)/i, + // Chrome/OmniWeb/Arora/Dolphin/Tizen/Nokia + ], ['name', 'version', 'major'], [ + /(?:android.+(crmo|crios))\/((\d+)?[\w\.]+)/i, // Chrome for Android/iOS + ], [['name', 'Chrome'], 'version', 'major'], [ + /(mobile\ssafari|safari|konqueror)\/((\d+)?[\w\.]+)/i, // Safari/Konqueror + /(applewebkit|khtml)\/((\d+)?[\w\.]+)/i, + + // Gecko based + /(iceweasel|camino|fennec|maemo\sbrowser|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'] + ], + + device : [[ + + /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook + /(blackberry)[\s-]?(\w+)/i, // BlackBerry + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte)[\s_-]?([\w-]+)*/i, + // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE + /(hp)\s([\w\s]+\w)/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'], [ + + /((transfo[prime\s]{4,10}\s\w+))|(?:android.*)((eeepc))/i // Asus + ], [['name', 'Asus'], 'version'], [ + + /(sie)-(\w+)*/i // Siemens + ], [['name', 'Siemens'], 'version'], [ + + /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia + /(nokia)[\s_-]?([\w-]+)*/i + ], [['name', 'Nokia'], 'version'] + ], + + engine : [[ + + /(presto)\/([\w\.]+)/i, // Presto + /([aple]*webkit|trident)\/([\w\.]+)/i, // Webkit/Trident + /(khtml)\/([\w\.]+)/i // KHTML + ], ['name', 'version'], [ + + /rv\:([\w\.]+).*(gecko)/i // Gecko + ], ['version', 'name'] + ], + + os : [[ + + // Windows based + /(windows\sphone\sos|windows)\s?([nt\d\.\s]+\d)/i // Windows + ], ['name', ['version', /(.+)/gi, maps.os.windows.version]], [ + /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i + ], [['name', 'Windows'], ['version', /(.+)/gi, maps.os.windows.version]], [ + + // Mobile/Embedded OS + /(blackberry).+version\/([\w\.]+)/i, // Blackberry + /(tizen)\/([\w\.]+)/i, // Tizen + /(android|symbianos|symbos|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i, + // Android/Symbian/WebOS/Palm/QNX/Bada/RIM/MeeGo + /(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]+\d)/i // Chromium OS + ], [['name', 'Chromium OS'], 'version'],[ + + // Solaris + /(sunos)\s?([\w\.\s]+\d)*/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\.]+\w)/i, // Mac OS + ], ['name', ['version', /_/g, '.']], [ + + // Other + /(haiku)\s(\w+)/i, // Haiku + /(macintosh|unix|minix|beos)[\/\s]?()*/i // UNIX/Minix/BeOS + ], ['name', 'version'] + ] + }; var UAParser = function UAParser (uastring) { var ua = uastring || (typeof window !== 'undefined' ? window.navigator.userAgent : ""); this.getBrowser = function () { + return mapper.regex.apply(this, regexes.browser); + }; - return regexMapper(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).+version\/((\d+)?[\w\.]+)/i, // Opera - /(opera)[\/\s]+((\d+)?[\w\.]+)/i, - - // 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|silk)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany - /(chrome|omniweb|arora|dolfin|[tizenaok]{5}\s?browser)\/((\d+)?[\w\.]+)/i, - // Chrome/OmniWeb/Arora/Dolphin/Tizen/Nokia - ], ['name', 'version', 'major'], [ - /(?:android.+(crmo|crios))\/((\d+)?[\w\.]+)/i, // Chrome for Android/iOS - ], [['name', 'Chrome'], 'version', 'major'], [ - /(mobile\ssafari|safari|konqueror)\/((\d+)?[\w\.]+)/i, // Safari/Konqueror - /(applewebkit|khtml)\/((\d+)?[\w\.]+)/i, - - // Gecko based - /(iceweasel|camino|fennec|maemo\sbrowser|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.getDevice = function () { + return mapper.regex.apply(this, regexes.device); }; this.getEngine = function () { - - return regexMapper(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']); + return mapper.regex.apply(this, regexes.engine); }; - this.getOS = function () { - - return regexMapper(ua, [ - - // Windows based - /(windows\sphone\sos|windows)\s?([nt\d\.\s]+\d)/i // Windows - ], ['name', ['version', /(.+)/gi, maps.os.win]], [ - /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i - ], [['name', 'Windows'], ['version', /(.+)/gi, maps.os.win]], [ - - // Mobile/Embedded OS - /(blackberry).+version\/([\w\.]+)/i, // Blackberry - /(tizen)\/([\w\.]+)/i, // Tizen - /(android|symbianos|symbos|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i, - // Android/Symbian/WebOS/Palm/QNX/Bada/RIM/MeeGo - /(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]+\d)/i // Chromium OS - ], [['name', 'Chromium OS'], 'version'],[ - - // Solaris - /(sunos)\s?([\w\.\s]+\d)*/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\.]+\w)/i, // Mac OS - ], ['name', ['version', /_/g, '.']], [ - - // Other - /(haiku)\s(\w+)/i, // Haiku - /(macintosh|unix|minix|beos)[\/\s]?()*/i // UNIX/Minix/BeOS - ], ['name', 'version']); - }; - - this.getDevice = function () { - - return regexMapper(ua, [ - - /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook - /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte)[\s_-]?([\w-]+)*/i, - // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE - /(hp)\s([\w\s]+\w)/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'], [ - - /((transfo[prime\s]{4,10}\s\w+))|(?:android.*)((eeepc))/i // Asus - ], [['name', 'Asus'], 'version'], [ - - /(sie)-(\w+)*/i // Siemens - ], [['name', 'Siemens'], 'version'], [ - - /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia - /(nokia)[\s_-]?([\w-]+)*/i - ], [['name', 'Nokia'], 'version']); - }; - - this.getUA = function() { - return ua; + this.getOS = function () { + return mapper.regex.apply(this, regexes.os); }; this.getResult = function() { @@ -245,6 +258,10 @@ device : this.getDevice() }; }; + + this.getUA = function() { + return ua; + }; this.setUA = function (uastring) { ua = uastring; From e5be3083cf2a64e7a462382caef764c072050a26 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Sat, 15 Sep 2012 14:18:49 +0700 Subject: [PATCH 08/13] Use strict --- ua-parser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ua-parser.js b/ua-parser.js index 29783c9..dde9d1a 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -7,6 +7,8 @@ (function (undefined) { + 'use strict'; + var mapper = { regex : function () { @@ -278,6 +280,6 @@ } exports.UAParser = UAParser; } else { - this['UAParser'] = UAParser; + window['UAParser'] = UAParser; } })(); From 41b3e247a4b8daaddec766b5edf0a2ef17cc97cd Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Mon, 17 Sep 2012 23:11:28 +0700 Subject: [PATCH 09/13] Add some Android browsers and some others --- ua-parser.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ua-parser.js b/ua-parser.js index dde9d1a..bd42f0e 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -103,7 +103,8 @@ // Mixed /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine)[\/\s]?((\d+)?[\w\.]+)/i, // Lunascape/Maxthon/Netfront/Jasmine + /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer // Presto based /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini @@ -116,7 +117,8 @@ /ms(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer // Webkit/KHTML based - /(chromium|flock|rockmelt|midori|epiphany|silk)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany + /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|series60|bolt)\/((\d+)?[\w\.]+)/i, + // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/S60/Bolt /(chrome|omniweb|arora|dolfin|[tizenaok]{5}\s?browser)\/((\d+)?[\w\.]+)/i, // Chrome/OmniWeb/Arora/Dolphin/Tizen/Nokia ], ['name', 'version', 'major'], [ @@ -133,7 +135,8 @@ /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla // Other - /(lynx|dillo|icab)[\/\s]?((\d+)?[\w\.]+)/i, // Lynx/Dillo/iCab + /(lynx|dillo|icab|doris)[\/\s]?((\d+)?[\w\.]+)/i, // Lynx/Dillo/iCab/Doris + /(gobrowser)\/?[\d\.]*/i // GoBrowser ], ['name', 'version', 'major'] ], @@ -141,8 +144,8 @@ /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte)[\s_-]?([\w-]+)*/i, - // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte|huawei)[\s_-]?([\w-]+)*/i, + // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE/Huawei /(hp)\s([\w\s]+\w)/i, // HP iPAQ /(hp).+(touchpad)/i, // HP TouchPad /(kindle)\/([\w\.]+)/i, // Kindle @@ -188,7 +191,7 @@ os : [[ // Windows based - /(windows\sphone\sos|windows)\s?([nt\d\.\s]+\d)/i // Windows + /(windows\sphone\sos|windows)\s?([ntce\d\.\s]+\d)/i // Windows ], ['name', ['version', /(.+)/gi, maps.os.windows.version]], [ /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i ], [['name', 'Windows'], ['version', /(.+)/gi, maps.os.windows.version]], [ From bf9c8de5c41428d741c1aefc2fba7b2787de1e9f Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Mon, 17 Sep 2012 23:37:41 +0700 Subject: [PATCH 10/13] Maps object should contains only data --- package.json | 2 +- ua-parser.js | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 9f5e7eb..42e9d65 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.4.0", + "version": "0.4.1", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/ua-parser.js b/ua-parser.js index bd42f0e..d1e9344 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.4.0 +// UA-Parser.JS v0.4.1 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -45,7 +45,11 @@ if (typeof props[k] === 'object' && props[k].length === 2) { result[props[k][0]] = props[k][1]; } else if (typeof props[k] === 'object' && props[k].length === 3) { - result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; + if (typeof props[k][1] === 'function') { + result[props[k][0]] = m ? props[k][1].call(this, m, props[k][2]) : undefined; + } else { + result[props[k][0]] = m ? m.replace(props[k][1], props[k][2]) : undefined; + } } else { result[props[k]] = m ? m : undefined; } @@ -81,17 +85,15 @@ var maps = { os : { windows : { - version : function (match, str1) { - return mapper.string(str1, { - 'ME' : '4.90', - 'NT 3.11' : 'nt3.51', - 'NT 4.0' : 'nt4.0', - '2000' : 'nt 5.0', - 'XP' : ['nt 5.1', 'nt 5.2'], - 'Vista' : 'nt 6.0', - '7' : 'nt 6.1', - '8' : 'nt 6.2' - }); + version : { + 'ME' : '4.90', + 'NT 3.11' : 'nt3.51', + 'NT 4.0' : 'nt4.0', + '2000' : 'nt 5.0', + 'XP' : ['nt 5.1', 'nt 5.2'], + 'Vista' : 'nt 6.0', + '7' : 'nt 6.1', + '8' : 'nt 6.2' } } } @@ -192,9 +194,9 @@ // Windows based /(windows\sphone\sos|windows)\s?([ntce\d\.\s]+\d)/i // Windows - ], ['name', ['version', /(.+)/gi, maps.os.windows.version]], [ + ], ['name', ['version', mapper.string, maps.os.windows.version]], [ /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i - ], [['name', 'Windows'], ['version', /(.+)/gi, maps.os.windows.version]], [ + ], [['name', 'Windows'], ['version', mapper.string, maps.os.windows.version]], [ // Mobile/Embedded OS /(blackberry).+version\/([\w\.]+)/i, // Blackberry @@ -223,7 +225,7 @@ ], ['name', 'version'],[ /(ip[honead]+).*os\s*([\w]+)*\slike\smac/i // iOS - ], [['name', /.+/g, 'iOS'], ['version', /_/g, '.']], [ + ], [['name', 'iOS'], ['version', /_/g, '.']], [ /(mac\sos\sx)\s([\w\s\.]+\w)/i, // Mac OS ], ['name', ['version', /_/g, '.']], [ From bdeefcd1fba212e7c40751fa2fad433df9d1f656 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Thu, 20 Sep 2012 01:43:16 +0700 Subject: [PATCH 11/13] New identifier for device: type (Mobile, Tablet, Console) --- package.json | 2 +- readme.md | 3 +- ua-parser.js | 88 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index 42e9d65..d03cae5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.4.1", + "version": "0.4.2", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/readme.md b/readme.md index 53ccb77..58c9fea 100644 --- a/readme.md +++ b/readme.md @@ -63,7 +63,8 @@ Extract detailed type of web browser, layout engine, operating system, and devic console.log(parser.getResult().os); // {name: "Ubuntu", version: "11.10"} // let's take another test please - console.log(parser.setUA("Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)").getOS().name); // "OpenBSD" + console.log(parser.setUA("Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)").getBrowser().name); // "Konqueror" + console.log(parser.getOS()); // {name: "OpenBSD", version: undefined} ``` diff --git a/ua-parser.js b/ua-parser.js index d1e9344..a499e61 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.4.1 +// UA-Parser.JS v0.4.2 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -8,7 +8,7 @@ (function (undefined) { 'use strict'; - + var mapper = { regex : function () { @@ -69,11 +69,11 @@ if (map.hasOwnProperty(i)) { if (typeof map[i] === 'object' && map[i].length > 0) { for (var j = 0; j < map[i].length; j++) { - if (str.toLowerCase().indexOf(map[i][j]) !== -1) { + if (str.toLowerCase().indexOf(map[i][j].toLowerCase()) !== -1) { return i; } } - } else if (str.toLowerCase().indexOf(map[i]) !== -1) { + } else if (str.toLowerCase().indexOf(map[i].toLowerCase()) !== -1) { return i; } } @@ -87,13 +87,13 @@ windows : { version : { 'ME' : '4.90', - 'NT 3.11' : 'nt3.51', - 'NT 4.0' : 'nt4.0', - '2000' : 'nt 5.0', - 'XP' : ['nt 5.1', 'nt 5.2'], - 'Vista' : 'nt 6.0', - '7' : 'nt 6.1', - '8' : 'nt 6.2' + 'NT 3.11' : 'NT3.51', + 'NT 4.0' : 'NT4.0', + '2000' : 'NT 5.0', + 'XP' : ['NT 5.1', 'NT 5.2'], + 'Vista' : 'NT 6.0', + '7' : 'NT 6.1', + '8' : 'NT 6.2' } } } @@ -111,8 +111,8 @@ // Presto based /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini /(opera\smobi)\/((\d+)?[\w\.-]+)/i, // Opera Mobile - /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera - /(opera)[\/\s]+((\d+)?[\w\.]+)/i, + /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80 + /(opera)[\/\s]+((\d+)?[\w\.]+)/i, // Opera < 9.80 // Trident based /(avant\sbrowser|iemobile|slimbrowser)[\/\s]?((\d+)?[\w\.]*)/i, // Avant/IEMobile/SlimBrowser @@ -121,7 +121,7 @@ // Webkit/KHTML based /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|series60|bolt)\/((\d+)?[\w\.]+)/i, // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/S60/Bolt - /(chrome|omniweb|arora|dolfin|[tizenaok]{5}\s?browser)\/((\d+)?[\w\.]+)/i, + /(chrome|omniweb|arora|dolfin|[tizenoka]{5}\s?browser)\/((\d+)?[\w\.]+)/i, // Chrome/OmniWeb/Arora/Dolphin/Tizen/Nokia ], ['name', 'version', 'major'], [ /(?:android.+(crmo|crios))\/((\d+)?[\w\.]+)/i, // Chrome for Android/iOS @@ -145,38 +145,60 @@ device : [[ /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook - /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte|huawei)[\s_-]?([\w-]+)*/i, - // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE/Huawei - /(hp)\s([\w\s]+\w)/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'], [ + /\s(nook)[\w\s]+build\/(\w+)/i, // Nook + /(dell)\s(strea[kpr\s\d]*[\dko])/i // Dell Streak + ], ['name', 'version', ['type', 'Tablet']], [ + + /(blackberry)[\s-]?(\w+)/i, // BlackBerry + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte|huawei|meizu)[\s_-]?([\w-]+)*/i, + // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE/Huawei/Meizu + /(hp)\s([\w\s]+\w)/i // HP iPAQ + ], ['name', 'version', ['type', 'Mobile']], [ - /(htc)[;_\s-]+([\w\s]+(?=\))|[\w]+)*/i, // HTC - /(zte)-([\w]+)*/i - ], ['name', ['version', /_/g, ' ']], [ + /(sony)\s(tablet\s[ps])/i // Sony + ], ['name', 'version', ['type', 'Tablet']], [ + + /(nintendo|playstation)\s([wids3portablev]+)/i // Nintendo/Playstation + ], ['name', 'version', ['type', 'Console']], [ + + /(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i, // HTC + /(zte)-(\w+)*/i + ], ['name', ['version', /_/g, ' '], ['type', 'Mobile']], [ - /\s((milestone|mz601|droid[2x]?|xoom))[globa\s]*\sbuild\//i, // Motorola + /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, // Motorola /(mot)[\s-]?(\w+)*/i - ], [['name', 'Motorola'], 'version'], [ - - /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i, // Samsung + ], [['name', 'Motorola'], 'version', ['type', 'Mobile']], [ + /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i + ], [['name', 'Motorola'], 'version', ['type', 'Tablet']], [ + // Samsung + /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i + ], [['name', 'Samsung'], 'version', ['type', 'Tablet']], [ + /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i, /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i, /sec-((sgh\w+))/i - ], [['name', 'Samsung'], 'version'], [ + ], [['name', 'Samsung'], 'version', ['type', 'Mobile']], [ - /((transfo[prime\s]{4,10}\s\w+))|(?:android.*)((eeepc))/i // Asus - ], [['name', 'Asus'], 'version'], [ + /(asus)-?(\w+)/i // Asus + ], ['name', 'version', ['type', 'Mobile']], [ + /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i + ], [['name', 'Asus'], 'version', ['type', 'Tablet']], [ /(sie)-(\w+)*/i // Siemens - ], [['name', 'Siemens'], 'version'], [ + ], [['name', 'Siemens'], 'version', ['type', 'Mobile']], [ /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia /(nokia)[\s_-]?([\w-]+)*/i - ], [['name', 'Nokia'], 'version'] + ], [['name', 'Nokia'], 'version', ['type', 'Mobile']], [ + + /android\s3\.[\s\w-;]{10}((a\d{3}))/i // Acer + ], [['name', 'Acer'], 'version', ['type', 'Tablet']], [ + + /android\s3\.[\s\w-;]{10}(lg?)-([06cv9]{3,4})/i // LG + ], [['name', 'LG'], 'version', ['type', 'Tablet']], [ + /(lg)[e;\s-]+(\w+)*/i + ], [['name', 'LG'], 'version', ['type', 'Mobile']] ], engine : [[ From b9843b4108a10f6e3c0be8fcbd869bf4af348933 Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Fri, 21 Sep 2012 22:59:30 +0700 Subject: [PATCH 12/13] Change device properties naming into more appropriate names --- ua-parser.js | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/ua-parser.js b/ua-parser.js index a499e61..ab0e448 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -144,61 +144,59 @@ device : [[ - /\((ip[honead]+|playbook);/i, // iPod/iPhone/iPad/PlayBook + /\(((ip[honead]+|playbook));/i, // iPod/iPhone/iPad/PlayBook /(hp).+(touchpad)/i, // HP TouchPad /(kindle)\/([\w\.]+)/i, // Kindle /\s(nook)[\w\s]+build\/(\w+)/i, // Nook /(dell)\s(strea[kpr\s\d]*[\dko])/i // Dell Streak - ], ['name', 'version', ['type', 'Tablet']], [ + ], ['vendor', 'model', ['type', 'Tablet']], [ /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|zte|huawei|meizu)[\s_-]?([\w-]+)*/i, - // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/ZTE/Huawei/Meizu + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|huawei|meizu)[\s_-]?([\w-]+)*/i, + // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/Huawei/Meizu /(hp)\s([\w\s]+\w)/i // HP iPAQ - ], ['name', 'version', ['type', 'Mobile']], [ + /(asus)-?(\w+)/i // Asus + ], ['vendor', 'model', ['type', 'Mobile']], [ - /(sony)\s(tablet\s[ps])/i // Sony - ], ['name', 'version', ['type', 'Tablet']], [ + /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i // Asus Tablets + ], [['vendor', 'Asus'], 'model', ['type', 'Tablet']], [ + + /(sony)\s(tablet\s[ps])/i // Sony Tablets + ], ['vendor', 'model', ['type', 'Tablet']], [ /(nintendo|playstation)\s([wids3portablev]+)/i // Nintendo/Playstation - ], ['name', 'version', ['type', 'Console']], [ + ], ['vendor', 'model', ['type', 'Console']], [ /(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i, // HTC - /(zte)-(\w+)*/i - ], ['name', ['version', /_/g, ' '], ['type', 'Mobile']], [ + /(zte)-(\w+)*/i // ZTE + ], ['vendor', ['model', /_/g, ' '], ['type', 'Mobile']], [ /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, // Motorola /(mot)[\s-]?(\w+)*/i - ], [['name', 'Motorola'], 'version', ['type', 'Mobile']], [ + ], [['vendor', 'Motorola'], 'model', ['type', 'Mobile']], [ /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i - ], [['name', 'Motorola'], 'version', ['type', 'Tablet']], [ - // Samsung + ], [['vendor', 'Motorola'], 'model', ['type', 'Tablet']], [ + /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i - ], [['name', 'Samsung'], 'version', ['type', 'Tablet']], [ + ], [['vendor', 'Samsung'], 'model', ['type', 'Tablet']], [ // Samsung /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i, /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i, /sec-((sgh\w+))/i - ], [['name', 'Samsung'], 'version', ['type', 'Mobile']], [ - - /(asus)-?(\w+)/i // Asus - ], ['name', 'version', ['type', 'Mobile']], [ - /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i - ], [['name', 'Asus'], 'version', ['type', 'Tablet']], [ - + ], [['vendor', 'Samsung'], 'model', ['type', 'Mobile']], [ /(sie)-(\w+)*/i // Siemens - ], [['name', 'Siemens'], 'version', ['type', 'Mobile']], [ + ], [['vendor', 'Siemens'], 'model', ['type', 'Mobile']], [ /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia /(nokia)[\s_-]?([\w-]+)*/i - ], [['name', 'Nokia'], 'version', ['type', 'Mobile']], [ + ], [['vendor', 'Nokia'], 'model', ['type', 'Mobile']], [ /android\s3\.[\s\w-;]{10}((a\d{3}))/i // Acer - ], [['name', 'Acer'], 'version', ['type', 'Tablet']], [ + ], [['vendor', 'Acer'], 'model', ['type', 'Tablet']], [ /android\s3\.[\s\w-;]{10}(lg?)-([06cv9]{3,4})/i // LG - ], [['name', 'LG'], 'version', ['type', 'Tablet']], [ + ], [['vendor', 'LG'], 'model', ['type', 'Tablet']], [ /(lg)[e;\s-]+(\w+)*/i - ], [['name', 'LG'], 'version', ['type', 'Mobile']] + ], [['vendor', 'LG'], 'model', ['type', 'Mobile']] ], engine : [[ From 3f92a3cb1079a61dfd2cb1339ad61f331e5feebc Mon Sep 17 00:00:00 2001 From: Faisal Salman Date: Fri, 21 Sep 2012 23:20:49 +0700 Subject: [PATCH 13/13] Fix readme & version --- package.json | 2 +- readme.md | 9 ++++++--- ua-parser.js | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index d03cae5..dd288de 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "title": "UA-Parser.JS", "name": "ua-parser-js", - "version": "0.4.2", + "version": "0.4.3", "author": "Faisal Salman (http://faisalman.com)", "description": "Lightweight JavaScript-based user-agent string parser", "keywords": [ diff --git a/readme.md b/readme.md index 58c9fea..0aacf17 100644 --- a/readme.md +++ b/readme.md @@ -48,8 +48,9 @@ Extract detailed type of web browser, layout engine, operating system, and devic version: "" }, device: { - name: "", - version: "" + model: "", + type: "", + vendor: "" } } */ @@ -59,12 +60,14 @@ Extract detailed type of web browser, layout engine, operating system, and devic parser.setUA(uastr); console.log(parser.getResult().browser); // {name: "Chromium", major: "15", version: "15.0.874.106"} + console.log(parser.getResult().device); // {model: undefined, type: undefined, vendor: undefined} console.log(parser.getResult().engine); // {name: "AppleWebKit", version: "535.2"} console.log(parser.getResult().os); // {name: "Ubuntu", version: "11.10"} // let's take another test please console.log(parser.setUA("Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)").getBrowser().name); // "Konqueror" console.log(parser.getOS()); // {name: "OpenBSD", version: undefined} + console.log(parser.getEngine()); // {name: "KHTML", version: "4.1.4"} ``` @@ -75,7 +78,7 @@ var UAParser = require('ua-parser'); var parser = new UAParser(); var uaString = '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'; -console.log(parser.setUA(uaString).getDevice().name); // "PlayBook" +console.log(parser.setUA(uaString).getDevice().model); // "PlayBook" console.log(parser.getOS()) // {name: "RIM Tablet OS", version: "1.0.0"} console.log(parser.getEngine().name); // "AppleWebKit" ``` diff --git a/ua-parser.js b/ua-parser.js index ab0e448..4e24ad2 100644 --- a/ua-parser.js +++ b/ua-parser.js @@ -1,4 +1,4 @@ -// UA-Parser.JS v0.4.2 +// UA-Parser.JS v0.4.3 // Lightweight JavaScript-based User-Agent string parser // https://github.com/faisalman/ua-parser-js // @@ -154,7 +154,7 @@ /(blackberry)[\s-]?(\w+)/i, // BlackBerry /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|nexus|huawei|meizu)[\s_-]?([\w-]+)*/i, // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Nexus/Huawei/Meizu - /(hp)\s([\w\s]+\w)/i // HP iPAQ + /(hp)\s([\w\s]+\w)/i, // HP iPAQ /(asus)-?(\w+)/i // Asus ], ['vendor', 'model', ['type', 'Mobile']], [