Comparing version 1.0.0 to 1.1.0
@@ -1,2 +0,2 @@ | ||
Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> | ||
Copyright 2011-2014 John-David Dalton <http://allyoucanleet.com/> | ||
@@ -3,0 +3,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
{ | ||
"name": "platform", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "A platform detection library that works on nearly all JavaScript platforms.", | ||
"homepage": "https://github.com/bestiejs/platform.js", | ||
"main": "platform", | ||
"keywords": [ | ||
"environment", | ||
"platform", | ||
"ua", | ||
"useragent" | ||
"license": "MIT", | ||
"main": "platform.js", | ||
"keywords": ["environment", "platform", "ua", "useragent"], | ||
"author": "John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)", | ||
"contributors": [ | ||
"John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)", | ||
"Benjamin Tan <demoneaux@gmail.com> (http://d10.github.io/)", | ||
"Mathias Bynens <mathias@qiwi.be> (http://mathiasbynens.be/)" | ||
], | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "http://mths.be/mit" | ||
} | ||
"bugs": "https://github.com/bestiejs/platform.js/issues", | ||
"repository": "bestiejs/platform.js", | ||
"scripts": { "test": "echo \"See the repository CONTRIBUTING.md for testing instructions.\"" }, | ||
"engines": ["node", "rhino"], | ||
"files": [ | ||
"LICENSE.txt", | ||
"platform.js" | ||
], | ||
"author": { | ||
"name": "John-David Dalton", | ||
"email": "john@fusejs.com", | ||
"web": "http://allyoucanleet.com/" | ||
}, | ||
"maintainers": [ | ||
{ | ||
"name": "John-David Dalton", | ||
"email": "john.david.dalton@gmail.com", | ||
"web": "http://allyoucanleet.com/" | ||
}, | ||
{ | ||
"name": "Mathias Bynens", | ||
"email": "mathias@qiwi.be", | ||
"web": "http://mathiasbynens.be/" | ||
} | ||
], | ||
"bugs": { | ||
"url": "https://github.com/bestiejs/platform.js/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/bestiejs/platform.js.git" | ||
}, | ||
"engines": [ | ||
"node", | ||
"rhino" | ||
], | ||
"directories": { | ||
"doc": "./doc", | ||
"test": "./test" | ||
"jam": { | ||
"main": "platform.js", | ||
"include": [ | ||
"LICENSE.txt", | ||
"platform.js" | ||
] | ||
} | ||
} | ||
} |
613
platform.js
/*! | ||
* Platform.js v1.0.0 <http://mths.be/platform> | ||
* Copyright 2010-2012 John-David Dalton <http://allyoucanleet.com/> | ||
* Platform.js v1.1.0 <http://mths.be/platform> | ||
* Copyright 2010-2014 John-David Dalton <http://allyoucanleet.com/> | ||
* Available under MIT license <http://mths.be/mit> | ||
*/ | ||
;(function(window) { | ||
;(function() { | ||
'use strict'; | ||
/** Backup possible window/global object */ | ||
var oldWin = window; | ||
/** Used to determine if values are of the language type Object */ | ||
var objectTypes = { | ||
'function': true, | ||
'object': true | ||
}; | ||
/** Detect free variable `exports` */ | ||
var freeExports = typeof exports == 'object' && exports; | ||
/** Used as a reference to the global object */ | ||
var root = (objectTypes[typeof window] && window) || this; | ||
/** Detect free variable `global` */ | ||
var freeGlobal = typeof global == 'object' && global && | ||
(global == global.global ? (window = global) : global); | ||
/** Backup possible global object */ | ||
var oldRoot = root; | ||
/** Opera regexp */ | ||
var reOpera = /Opera/; | ||
/** Detect free variable `exports` */ | ||
var freeExports = objectTypes[typeof exports] && exports; | ||
/** Used to resolve a value's internal [[Class]] */ | ||
var toString = {}.toString; | ||
/** Detect free variable `module` */ | ||
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; | ||
/** Detect Java environment */ | ||
var java = /Java/.test(getClassOf(window.java)) && window.java; | ||
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ | ||
var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; | ||
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { | ||
root = freeGlobal; | ||
} | ||
/** A character to represent alpha */ | ||
var alpha = java ? 'a' : '\u03b1'; | ||
/** A character to represent beta */ | ||
var beta = java ? 'b' : '\u03b2'; | ||
/** Browser document object */ | ||
var doc = window.document || {}; | ||
/** Used to check for own properties of an object */ | ||
var hasOwnProperty = {}.hasOwnProperty; | ||
/** Browser navigator object */ | ||
var nav = window.navigator || {}; | ||
/** | ||
* Detect Opera browser | ||
* http://www.howtocreate.co.uk/operaStuff/operaObject.html | ||
* http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini | ||
* Used as the maximum length of an array-like object. | ||
* See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) | ||
* for more details. | ||
*/ | ||
var opera = window.operamini || window.opera; | ||
var maxSafeInteger = Math.pow(2, 53) - 1; | ||
/** Opera [[Class]] */ | ||
var operaClass = reOpera.test(operaClass = getClassOf(opera)) ? operaClass : (opera = null); | ||
/** Opera regexp */ | ||
var reOpera = /Opera/; | ||
@@ -56,5 +46,11 @@ /** Possible global object */ | ||
/** Browser user agent string */ | ||
var userAgent = nav.userAgent || ''; | ||
/** Used for native method references */ | ||
var objectProto = Object.prototype; | ||
/** Used to check for own properties of an object */ | ||
var hasOwnProperty = objectProto.hasOwnProperty; | ||
/** Used to resolve the internal `[[Class]]` of values */ | ||
var toString = objectProto.toString; | ||
/*--------------------------------------------------------------------------*/ | ||
@@ -66,4 +62,4 @@ | ||
* @private | ||
* @param {String} string The string to capitalize. | ||
* @returns {String} The capitalized string. | ||
* @param {string} string The string to capitalize. | ||
* @returns {string} The capitalized string. | ||
*/ | ||
@@ -84,5 +80,5 @@ function capitalize(string) { | ||
var index = -1, | ||
length = object.length; | ||
length = object ? object.length : 0; | ||
if (length == length >>> 0) { | ||
if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) { | ||
while (++index < length) { | ||
@@ -100,4 +96,4 @@ callback(object[index], index, object); | ||
* @private | ||
* @param {String} string The string to format. | ||
* @returns {String} The formatted string. | ||
* @param {string} string The string to format. | ||
* @returns {string} The formatted string. | ||
*/ | ||
@@ -120,3 +116,5 @@ function format(string) { | ||
for (var key in object) { | ||
hasKey(object, key) && callback(object[key], key, object); | ||
if (hasOwnProperty.call(object, key)) { | ||
callback(object[key], key, object); | ||
} | ||
} | ||
@@ -129,4 +127,4 @@ } | ||
* @private | ||
* @param {Mixed} value The value. | ||
* @returns {String} The [[Class]]. | ||
* @param {*} value The value. | ||
* @returns {string} The [[Class]]. | ||
*/ | ||
@@ -140,44 +138,10 @@ function getClassOf(value) { | ||
/** | ||
* Checks if an object has the specified key as a direct property. | ||
* | ||
* @private | ||
* @param {Object} object The object to check. | ||
* @param {String} key The key to check for. | ||
* @returns {Boolean} Returns `true` if key is a direct property, else `false`. | ||
*/ | ||
function hasKey() { | ||
// lazy define for others (not as accurate) | ||
hasKey = function(object, key) { | ||
var parent = object != null && (object.constructor || Object).prototype; | ||
return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); | ||
}; | ||
// for modern browsers | ||
if (getClassOf(hasOwnProperty) == 'Function') { | ||
hasKey = function(object, key) { | ||
return object != null && hasOwnProperty.call(object, key); | ||
}; | ||
} | ||
// for Safari 2 | ||
else if ({}.__proto__ == Object.prototype) { | ||
hasKey = function(object, key) { | ||
var result = false; | ||
if (object != null) { | ||
object = Object(object); | ||
object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; | ||
} | ||
return result; | ||
}; | ||
} | ||
return hasKey.apply(this, arguments); | ||
} | ||
/** | ||
* Host objects can return type values that are different from their actual | ||
* data type. The objects we are concerned with usually return non-primitive | ||
* types of object, function, or unknown. | ||
* types of "object", "function", or "unknown". | ||
* | ||
* @private | ||
* @param {Mixed} object The owner of the property. | ||
* @param {String} property The property to check. | ||
* @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. | ||
* @param {*} object The owner of the property. | ||
* @param {string} property The property to check. | ||
* @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`. | ||
*/ | ||
@@ -191,8 +155,7 @@ function isHostType(object, property) { | ||
/** | ||
* Prepares a string for use in a RegExp constructor by making hyphens and | ||
* spaces optional. | ||
* Prepares a string for use in a `RegExp` by making hyphens and spaces optional. | ||
* | ||
* @private | ||
* @param {String} string The string to qualify. | ||
* @returns {String} The qualified string. | ||
* @param {string} string The string to qualify. | ||
* @returns {string} The qualified string. | ||
*/ | ||
@@ -204,3 +167,3 @@ function qualify(string) { | ||
/** | ||
* A bare-bones` Array#reduce` like utility function. | ||
* A bare-bones `Array#reduce` like utility function. | ||
* | ||
@@ -210,4 +173,3 @@ * @private | ||
* @param {Function} callback The function called per iteration. | ||
* @param {Mixed} accumulator Initial value of the accumulator. | ||
* @returns {Mixed} The accumulator. | ||
* @returns {*} The accumulated result. | ||
*/ | ||
@@ -226,4 +188,4 @@ function reduce(array, callback) { | ||
* @private | ||
* @param {String} string The string to trim. | ||
* @returns {String} The trimmed string. | ||
* @param {string} string The string to trim. | ||
* @returns {string} The trimmed string. | ||
*/ | ||
@@ -240,3 +202,4 @@ function trim(string) { | ||
* @memberOf platform | ||
* @param {String} [ua = navigator.userAgent] The user agent string. | ||
* @param {Object|string} [ua=navigator.userAgent] The user agent string or | ||
* context object. | ||
* @returns {Object} A platform object. | ||
@@ -246,4 +209,66 @@ */ | ||
/** The environment context object */ | ||
var context = root; | ||
/** Used to flag when a custom context is provided */ | ||
var isCustomContext = ua && typeof ua == 'object' && getClassOf(ua) != 'String'; | ||
// juggle arguments | ||
if (isCustomContext) { | ||
context = ua; | ||
ua = null; | ||
} | ||
/** Browser navigator object */ | ||
var nav = context.navigator || {}; | ||
/** Browser user agent string */ | ||
var userAgent = nav.userAgent || ''; | ||
ua || (ua = userAgent); | ||
/** Used to flag when `thisBinding` is the [ModuleScope] */ | ||
var isModuleScope = isCustomContext || thisBinding == oldRoot; | ||
/** Used to detect if browser is like Chrome */ | ||
var likeChrome = isCustomContext | ||
? !!nav.likeChrome | ||
: /\bChrome\b/.test(ua) && !/internal|\n/i.test(toString.toString()); | ||
/** Internal [[Class]] value shortcuts */ | ||
var objectClass = 'Object', | ||
airRuntimeClass = isCustomContext ? objectClass : 'ScriptBridgingProxyObject', | ||
enviroClass = isCustomContext ? objectClass : 'Environment', | ||
javaClass = (isCustomContext && context.java) ? 'JavaPackage' : getClassOf(context.java), | ||
phantomClass = isCustomContext ? objectClass : 'RuntimeObject'; | ||
/** Detect Java environment */ | ||
var java = /Java/.test(javaClass) && context.java; | ||
/** Detect Rhino */ | ||
var rhino = java && getClassOf(context.environment) == enviroClass; | ||
/** A character to represent alpha */ | ||
var alpha = java ? 'a' : '\u03b1'; | ||
/** A character to represent beta */ | ||
var beta = java ? 'b' : '\u03b2'; | ||
/** Browser document object */ | ||
var doc = context.document || {}; | ||
/** | ||
* Detect Opera browser | ||
* http://www.howtocreate.co.uk/operaStuff/operaObject.html | ||
* http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini | ||
*/ | ||
var opera = context.operamini || context.opera; | ||
/** Opera [[Class]] */ | ||
var operaClass = reOpera.test(operaClass = (isCustomContext && opera) ? opera['[[Class]]'] : getClassOf(opera)) | ||
? operaClass | ||
: (opera = null); | ||
/*------------------------------------------------------------------------*/ | ||
/** Temporary variable used over the script's lifetime */ | ||
@@ -292,3 +317,3 @@ var data; | ||
'Iceweasel', | ||
'Iron', | ||
{ 'label': 'SRWare Iron', 'pattern': 'Iron' }, | ||
'K-Meleon', | ||
@@ -313,2 +338,3 @@ 'Konqueror', | ||
'Opera', | ||
{ 'label': 'Opera', 'pattern': 'OPR' }, | ||
'Chrome', | ||
@@ -323,5 +349,8 @@ { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' }, | ||
var product = getProduct([ | ||
{ 'label': 'BlackBerry', 'pattern': 'BB10' }, | ||
'BlackBerry', | ||
{ 'label': 'Galaxy S', 'pattern': 'GT-I9000' }, | ||
{ 'label': 'Galaxy S2', 'pattern': 'GT-I9100' }, | ||
{ 'label': 'Galaxy S3', 'pattern': 'GT-I9300' }, | ||
{ 'label': 'Galaxy S4', 'pattern': 'GT-I9500' }, | ||
'Google TV', | ||
@@ -335,5 +364,11 @@ 'iPad', | ||
'PlayBook', | ||
'PlayStation 4', | ||
'PlayStation 3', | ||
'PlayStation Vita', | ||
'TouchPad', | ||
'Transformer', | ||
{ 'label': 'Wii U', 'pattern': 'WiiU' }, | ||
'Wii', | ||
'Xbox One', | ||
{ 'label': 'Xbox 360', 'pattern': 'Xbox' }, | ||
'Xoom' | ||
@@ -351,7 +386,10 @@ ]); | ||
'HP': { 'TouchPad': 1 }, | ||
'HTC': { }, | ||
'LG': { }, | ||
'Microsoft': { 'Xbox': 1, 'Xbox One': 1 }, | ||
'Motorola': { 'Xoom': 1 }, | ||
'Nintendo': { 'Wii U': 1, 'Wii': 1 }, | ||
'Nokia': { }, | ||
'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1 }, | ||
'Sony': { 'PlayStation Vita': 1 } | ||
'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1, 'Galaxy S3': 1, 'Galaxy S4': 1 }, | ||
'Sony': { 'PlayStation 4': 1, 'PlayStation 3': 1, 'PlayStation Vita': 1 } | ||
}); | ||
@@ -395,3 +433,3 @@ | ||
* @param {Array} guesses An array of guesses. | ||
* @returns {String|Null} The detected layout engine. | ||
* @returns {null|string} The detected layout engine. | ||
*/ | ||
@@ -410,4 +448,4 @@ function getLayout(guesses) { | ||
* @private | ||
* @param {Array} guesses An array of guesses. | ||
* @returns {String|Null} The detected manufacturer. | ||
* @param {Object} guesses An object of guesses. | ||
* @returns {null|string} The detected manufacturer. | ||
*/ | ||
@@ -420,4 +458,4 @@ function getManufacturer(guesses) { | ||
value[0/*Opera 9.25 fix*/, /^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] || | ||
RegExp('\\b' + (key.pattern || qualify(key)) + '(?:\\b|\\w*\\d)', 'i').exec(ua) | ||
) && (key.label || key); | ||
RegExp('\\b' + qualify(key) + '(?:\\b|\\w*\\d)', 'i').exec(ua) | ||
) && key; | ||
}); | ||
@@ -431,3 +469,3 @@ } | ||
* @param {Array} guesses An array of guesses. | ||
* @returns {String|Null} The detected browser name. | ||
* @returns {null|string} The detected browser name. | ||
*/ | ||
@@ -447,3 +485,3 @@ function getName(guesses) { | ||
* @param {Array} guesses An array of guesses. | ||
* @returns {String|Null} The detected OS name. | ||
* @returns {null|string} The detected OS name. | ||
*/ | ||
@@ -454,3 +492,4 @@ function getOS(guesses) { | ||
if (!result && (result = | ||
RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua))) { | ||
RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua) | ||
)) { | ||
// platform tokens defined at | ||
@@ -460,2 +499,3 @@ // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx | ||
data = { | ||
'6.3': '8.1', | ||
'6.2': '8', | ||
@@ -484,2 +524,3 @@ '6.1': 'Server 2008 R2 / 7', | ||
.replace(/(OS X) [^ \d]+/i, '$1') | ||
.replace(/Mac (OS X)/, '$1') | ||
.replace(/\/(\d)/, ' $1') | ||
@@ -500,3 +541,3 @@ .replace(/_/g, '.') | ||
* @param {Array} guesses An array of guesses. | ||
* @returns {String|Null} The detected product name. | ||
* @returns {null|string} The detected product name. | ||
*/ | ||
@@ -511,3 +552,3 @@ function getProduct(guesses) { | ||
// split by forward slash and append product version if needed | ||
if ((result = String(guess.label || result).split('/'))[1] && !/[\d.]+/.test(result[0])) { | ||
if ((result = String((guess.label && !RegExp(pattern, 'i').test(guess.label)) ? guess.label : result).split('/'))[1] && !/[\d.]+/.test(result[0])) { | ||
result[0] += ' ' + result[1]; | ||
@@ -520,3 +561,3 @@ } | ||
.replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ') | ||
.replace(RegExp('(' + guess + ')(\\w)', 'i'), '$1 $2')); | ||
.replace(RegExp('(' + guess + ')[-_.]?(\\w)', 'i'), '$1 $2')); | ||
} | ||
@@ -532,3 +573,3 @@ return result; | ||
* @param {Array} patterns An array of UA patterns. | ||
* @returns {String|Null} The detected version. | ||
* @returns {null|string} The detected version. | ||
*/ | ||
@@ -542,4 +583,2 @@ function getVersion(patterns) { | ||
/*------------------------------------------------------------------------*/ | ||
/** | ||
@@ -550,3 +589,3 @@ * Returns `platform.description` when the platform object is coerced to a string. | ||
* @memberOf platform | ||
* @returns {String} Returns `platform.description` if available, else an empty string. | ||
* @returns {string} Returns `platform.description` if available, else an empty string. | ||
*/ | ||
@@ -587,3 +626,3 @@ function toStringPlatform() { | ||
else if (manufacturer && manufacturer != 'Google' && | ||
/Chrome|Vita/.test(name + ';' + product)) { | ||
((/Chrome/.test(name) && !/Mobile Safari/.test(ua)) || /Vita/.test(product))) { | ||
name = 'Android Browser'; | ||
@@ -593,3 +632,3 @@ os = /Android/.test(os) ? os : 'Android'; | ||
// detect false positives for Firefox/Safari | ||
else if (!name || (data = !/\bMinefield\b/i.test(ua) && /Firefox|Safari/.exec(name))) { | ||
else if (!name || (data = !/\bMinefield\b|\(Android;/i.test(ua) && /Firefox|Safari/.exec(name))) { | ||
// escape the `/` for Firefox 1 | ||
@@ -606,6 +645,13 @@ if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) { | ||
} | ||
// detect Firefox OS | ||
if ((data = /\((Mobile|Tablet).*?Firefox/i.exec(ua)) && data[1]) { | ||
os = 'Firefox OS'; | ||
if (!product) { | ||
product = data[1]; | ||
} | ||
} | ||
// detect non-Opera versions (order is important) | ||
if (!version) { | ||
version = getVersion([ | ||
'(?:Cloud9|CriOS|CrMo|Opera ?Mini|Raven|Silk(?!/[\\d.]+$))', | ||
'(?:Cloud9|CriOS|CrMo|Iron|Opera ?Mini|OPR|Raven|Silk(?!/[\\d.]+$))', | ||
'Version', | ||
@@ -619,8 +665,18 @@ qualify(name), | ||
layout = ['WebKit']; | ||
} else if (data = | ||
/Opera/.test(name) && 'Presto' || | ||
/\b(?:Midori|Nook|Safari)\b/i.test(ua) && 'WebKit' || | ||
!layout && /\bMSIE\b/i.test(ua) && (/^Mac/.test(os) ? 'Tasman' : 'Trident')) { | ||
} else if ((data = | ||
/Opera/.test(name) && (/OPR/.test(ua) ? 'Blink' : 'Presto') || | ||
/\b(?:Midori|Nook|Safari)\b/i.test(ua) && 'WebKit' || | ||
!layout && /\bMSIE\b/i.test(ua) && (os == 'Mac OS' ? 'Tasman' : 'Trident') | ||
)) { | ||
layout = [data]; | ||
} | ||
// detect NetFront on PlayStation | ||
else if (/PlayStation(?! Vita)/i.test(name) && layout == 'WebKit') { | ||
layout = ['NetFront']; | ||
} | ||
// detect IE 11 and above | ||
if (!name && layout == 'Trident') { | ||
name = 'IE'; | ||
version = (/\brv:([\d.]+)/.exec(ua) || 0)[1]; | ||
} | ||
// leverage environment features | ||
@@ -630,3 +686,3 @@ if (useFeatures) { | ||
// Rhino has a global function while others have a global object | ||
if (isHostType(window, 'global')) { | ||
if (isHostType(context, 'global')) { | ||
if (java) { | ||
@@ -637,16 +693,16 @@ data = java.lang.System; | ||
} | ||
if (typeof exports == 'object' && exports) { | ||
// if `thisBinding` is the [ModuleScope] | ||
if (thisBinding == oldWin && typeof system == 'object' && (data = [system])[0]) { | ||
if (isHostType(context, 'exports')) { | ||
if (isModuleScope && isHostType(context, 'system') && (data = [context.system])[0]) { | ||
os || (os = data[0].os || null); | ||
try { | ||
data[1] = require('ringo/engine').version; | ||
data[1] = (data[1] = context.require) && data[1]('ringo/engine').version; | ||
version = data[1].join('.'); | ||
name = 'RingoJS'; | ||
} catch(e) { | ||
if (data[0].global == freeGlobal) { | ||
if (data[0].global.system == context.system) { | ||
name = 'Narwhal'; | ||
} | ||
} | ||
} else if (typeof process == 'object' && (data = process)) { | ||
} | ||
else if (typeof context.process == 'object' && (data = context.process)) { | ||
name = 'Node.js'; | ||
@@ -657,3 +713,7 @@ arch = data.arch; | ||
} | ||
} else if (getClassOf(window.environment) == 'Environment') { | ||
else if (rhino) { | ||
name = 'Rhino'; | ||
} | ||
} | ||
else if (rhino) { | ||
name = 'Rhino'; | ||
@@ -663,3 +723,3 @@ } | ||
// detect Adobe AIR | ||
else if (getClassOf(data = window.runtime) == 'ScriptBridgingProxyObject') { | ||
else if (getClassOf((data = context.runtime)) == airRuntimeClass) { | ||
name = 'Adobe AIR'; | ||
@@ -669,3 +729,3 @@ os = data.flash.system.Capabilities.os; | ||
// detect PhantomJS | ||
else if (getClassOf(data = window.phantom) == 'RuntimeObject') { | ||
else if (getClassOf((data = context.phantom)) == phantomClass) { | ||
name = 'PhantomJS'; | ||
@@ -681,3 +741,3 @@ version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch); | ||
description.push('IE ' + version[1] + ' mode'); | ||
layout[1] = ''; | ||
layout && (layout[1] = ''); | ||
version[1] = data; | ||
@@ -691,5 +751,6 @@ } | ||
if (version && (data = | ||
/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) || | ||
/(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) || | ||
/\bMinefield\b/i.test(ua) && 'a')) { | ||
/(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) || | ||
/(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) || | ||
/\bMinefield\b/i.test(ua) && 'a' | ||
)) { | ||
prerelease = /b/i.test(data) ? 'beta' : 'alpha'; | ||
@@ -699,4 +760,4 @@ version = version.replace(RegExp(data + '\\+?$'), '') + | ||
} | ||
// rename code name "Fennec" | ||
if (name == 'Fennec') { | ||
// detect Firefox Mobile | ||
if (name == 'Fennec' || name == 'Firefox' && /Android|Firefox OS/.test(os)) { | ||
name = 'Firefox Mobile'; | ||
@@ -720,8 +781,15 @@ } | ||
else if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) { | ||
name += ' Mobile'; | ||
os = 'Windows Phone OS ' + data + '.x'; | ||
description.unshift('desktop mode'); | ||
name += ' Mobile'; | ||
os = 'Windows Phone OS ' + data + '.x'; | ||
description.unshift('desktop mode'); | ||
} | ||
// detect Xbox 360 and Xbox One | ||
else if (/Xbox/i.test(product)) { | ||
os = null; | ||
if (product == 'Xbox 360' && /IEMobile/.test(ua)) { | ||
description.unshift('mobile mode'); | ||
} | ||
} | ||
// add mobile postfix | ||
else if ((name == 'IE' || name && !product && !/Browser|Mobi/.test(name)) && | ||
else if ((name == 'Chrome' || name == 'IE' || name && !product && !/Browser|Mobi/.test(name)) && | ||
(os == 'Windows CE' || /Mobi/i.test(ua))) { | ||
@@ -731,3 +799,3 @@ name += ' Mobile'; | ||
// detect IE platform preview | ||
else if (name == 'IE' && useFeatures && typeof external == 'object' && !external) { | ||
else if (name == 'IE' && useFeatures && context.external === null) { | ||
description.unshift('platform preview'); | ||
@@ -737,6 +805,8 @@ } | ||
// http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp | ||
else if (/BlackBerry/.test(product) && (data = | ||
(RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] || | ||
version)) { | ||
os = 'Device Software ' + data; | ||
else if ((/BlackBerry/.test(product) || /BB10/.test(ua)) && (data = | ||
(RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] || | ||
version | ||
)) { | ||
data = [data, /BB10/.test(ua)]; | ||
os = (data[1] ? (product = null, manufacturer = 'BlackBerry') : 'Device Software') + ' ' + data[0]; | ||
version = null; | ||
@@ -747,11 +817,13 @@ } | ||
else if (this != forOwn && ( | ||
(useFeatures && opera) || | ||
(/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) || | ||
(name == 'Firefox' && /OS X (?:\d+\.){2,}/.test(os)) || | ||
(name == 'IE' && ( | ||
(os && !/^Win/.test(os) && version > 5.5) || | ||
/Windows XP/.test(os) && version > 8 || | ||
version == 8 && !/Trident/.test(ua) | ||
)) | ||
) && !reOpera.test(data = parse.call(forOwn, ua.replace(reOpera, '') + ';')) && data.name) { | ||
product != 'Wii' && ( | ||
(useFeatures && opera) || | ||
(/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) || | ||
(name == 'Firefox' && /OS X (?:\d+\.){2,}/.test(os)) || | ||
(name == 'IE' && ( | ||
(os && !/^Win/.test(os) && version > 5.5) || | ||
/Windows XP/.test(os) && version > 8 || | ||
version == 8 && !/Trident/.test(ua) | ||
)) | ||
) | ||
) && !reOpera.test((data = parse.call(forOwn, ua.replace(reOpera, '') + ';'))) && data.name) { | ||
@@ -797,19 +869,22 @@ // when "indentifying", the UA contains both Opera and the other browser's name | ||
else if (version == data[1] || | ||
version == (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1]) { | ||
version == (data[2] = (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { | ||
version = null; | ||
} | ||
// use the full Chrome version when available | ||
data = [data[0], (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]]; | ||
data[1] = (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]; | ||
// detect Blink layout engine | ||
if (data[0] == 537.36 && data[2] == 537.36 && parseFloat(data[1]) >= 28) { | ||
layout = ['Blink']; | ||
} | ||
// detect JavaScriptCore | ||
// http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi | ||
if (!useFeatures || (/internal|\n/i.test(toString.toString()) && !data[1])) { | ||
layout[1] = 'like Safari'; | ||
data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : '5'); | ||
if (!useFeatures || (!likeChrome && !data[1])) { | ||
layout && (layout[1] = 'like Safari'); | ||
data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : data < 537 ? 6 : data < 538 ? 7 : '7'); | ||
} else { | ||
layout[1] = 'like Chrome'; | ||
data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : '21'); | ||
layout && (layout[1] = 'like Chrome'); | ||
data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : data < 537.11 ? '21+' : data < 537.13 ? 23 : data < 537.18 ? 24 : data < 537.24 ? 25 : data < 537.36 ? 26 : layout != 'Blink' ? '27' : '28'); | ||
} | ||
// add the postfix of ".x" or "+" for approximate versions | ||
layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+'); | ||
layout && (layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+')); | ||
// obscure version for some Safari 1-2 releases | ||
@@ -832,3 +907,3 @@ if (name == 'Safari' && (!version || parseInt(version) > 45)) { | ||
// detect Chrome desktop mode | ||
else if (name == 'Safari' && /Chrome/.exec(layout[1])) { | ||
else if (name == 'Safari' && /Chrome/.exec(layout && layout[1])) { | ||
description.unshift('desktop mode'); | ||
@@ -838,3 +913,3 @@ name = 'Chrome Mobile'; | ||
if (/Mac OS X/.test(os)) { | ||
if (/OS X/.test(os)) { | ||
manufacturer = 'Apple'; | ||
@@ -847,3 +922,3 @@ os = 'iOS 4.3+'; | ||
// strip incorrect OS versions | ||
if (version && version.indexOf(data = /[\d.]+$/.exec(os)) == 0 && | ||
if (version && version.indexOf((data = /[\d.]+$/.exec(os))) == 0 && | ||
ua.indexOf('/' + data + '-') > -1) { | ||
@@ -885,6 +960,6 @@ os = trim(os.replace(data, '')); | ||
// add browser/OS architecture | ||
if ((data = / (?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { | ||
if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { | ||
if (os) { | ||
os.architecture = 64; | ||
os.family = os.family.replace(data, ''); | ||
os.family = os.family.replace(RegExp(' *' + data), ''); | ||
} | ||
@@ -907,119 +982,125 @@ if (name && (/WOW64/i.test(ua) || | ||
*/ | ||
return { | ||
var platform = {}; | ||
/** | ||
* The browser/environment version. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
*/ | ||
'version': name && version && (description.unshift(version), version), | ||
/** | ||
* The platform description. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.description = ua; | ||
/** | ||
* The name of the browser/environment. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
*/ | ||
'name': name && (description.unshift(name), name), | ||
/** | ||
* The name of the browser's layout engine. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.layout = layout && layout[0]; | ||
/** | ||
* The name of the operating system. | ||
* | ||
* @memberOf platform | ||
* @type Object | ||
*/ | ||
'os': os | ||
? (name && | ||
!(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product)) && | ||
description.push(product ? '(' + os + ')' : 'on ' + os), os) | ||
: { | ||
/** | ||
* The name of the product's manufacturer. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.manufacturer = manufacturer; | ||
/** | ||
* The CPU architecture the OS is built for. | ||
* | ||
* @memberOf platform.os | ||
* @type String|Null | ||
*/ | ||
'architecture': null, | ||
/** | ||
* The name of the browser/environment. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.name = name; | ||
/** | ||
* The family of the OS. | ||
* | ||
* @memberOf platform.os | ||
* @type String|Null | ||
*/ | ||
'family': null, | ||
/** | ||
* The alpha/beta release indicator. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.prerelease = prerelease; | ||
/** | ||
* The version of the OS. | ||
* | ||
* @memberOf platform.os | ||
* @type String|Null | ||
*/ | ||
'version': null, | ||
/** | ||
* The name of the product hosting the browser. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.product = product; | ||
/** | ||
* Returns the OS string. | ||
* | ||
* @memberOf platform.os | ||
* @returns {String} The OS string. | ||
*/ | ||
'toString': function() { return 'null'; } | ||
}, | ||
/** | ||
* The browser's user agent string. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.ua = ua; | ||
/** | ||
* The platform description. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
*/ | ||
'description': description.length ? description.join(' ') : ua, | ||
/** | ||
* The browser/environment version. | ||
* | ||
* @memberOf platform | ||
* @type string|null | ||
*/ | ||
platform.version = name && version; | ||
/** | ||
* The name of the browser layout engine. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
*/ | ||
'layout': layout && layout[0], | ||
/** | ||
* The name of the operating system. | ||
* | ||
* @memberOf platform | ||
* @type Object | ||
*/ | ||
platform.os = os || { | ||
/** | ||
* The name of the product's manufacturer. | ||
* The CPU architecture the OS is built for. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
* @memberOf platform.os | ||
* @type number|null | ||
*/ | ||
'manufacturer': manufacturer, | ||
'architecture': null, | ||
/** | ||
* The alpha/beta release indicator. | ||
* The family of the OS. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
* @memberOf platform.os | ||
* @type string|null | ||
*/ | ||
'prerelease': prerelease, | ||
'family': null, | ||
/** | ||
* The name of the product hosting the browser. | ||
* The version of the OS. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
* @memberOf platform.os | ||
* @type string|null | ||
*/ | ||
'product': product, | ||
'version': null, | ||
/** | ||
* The browser's user agent string. | ||
* Returns the OS string. | ||
* | ||
* @memberOf platform | ||
* @type String|Null | ||
* @memberOf platform.os | ||
* @returns {string} The OS string. | ||
*/ | ||
'ua': ua, | ||
'toString': function() { return 'null'; } | ||
}; | ||
// parses a user agent string into a platform object | ||
'parse': parse, | ||
platform.parse = parse; | ||
platform.toString = toStringPlatform; | ||
// returns the platform description | ||
'toString': toStringPlatform | ||
}; | ||
if (platform.version) { | ||
description.unshift(version); | ||
} | ||
if (platform.name) { | ||
description.unshift(name); | ||
} | ||
if (os && name && !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product))) { | ||
description.push(product ? '(' + os + ')' : 'on ' + os); | ||
} | ||
if (description.length) { | ||
platform.description = description.join(' '); | ||
} | ||
return platform; | ||
} | ||
@@ -1029,4 +1110,4 @@ | ||
// expose platform | ||
// some AMD build optimizers, like r.js, check for specific condition patterns like the following: | ||
// export platform | ||
// some AMD build optimizers, like r.js, check for condition patterns like the following: | ||
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { | ||
@@ -1039,4 +1120,4 @@ // define as an anonymous module so, through path mapping, it can be aliased | ||
// check for `exports` after `define` in case a build optimizer adds an `exports` object | ||
else if (freeExports) { | ||
// in Narwhal, Node.js, or RingoJS | ||
else if (freeExports && freeModule) { | ||
// in Narwhal, Node.js, Rhino -require, or RingoJS | ||
forOwn(parse(), function(value, key) { | ||
@@ -1048,6 +1129,4 @@ freeExports[key] = value; | ||
else { | ||
// use square bracket notation so Closure Compiler won't munge `platform` | ||
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export | ||
window['platform'] = parse(); | ||
root.platform = parse(); | ||
} | ||
}(this)); | ||
}.call(this)); |
@@ -1,2 +0,2 @@ | ||
# Platform.js <sup>v1.0.0</sup> | ||
# Platform.js <sup>v1.1.0</sup> | ||
@@ -11,3 +11,3 @@ A platform detection library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>. | ||
Platform.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation. | ||
Platform.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5+ precedents, unit testing, and plenty of documentation. | ||
@@ -18,2 +18,3 @@ ## Documentation | ||
The full changelog for this release is available on our [wiki](https://github.com/bestiejs/platform.js/wiki/Changelog).<br> | ||
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/platform.js/wiki/Roadmap). | ||
@@ -23,33 +24,33 @@ | ||
Platform.js has been tested in at least Adobe AIR 3.1, Chrome 5-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.8.6, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. | ||
Tested in Chrome 34-35, Firefox 28-29, IE 6-11, Opera 20-21, Safari 5-7, Node.js 0.6.21~0.10.28, Narwhal 0.3.2, PhantomJS 1.9.2, RingoJS 0.9, & Rhino 1.7RC5. | ||
## Installation and usage | ||
In a browser or Adobe AIR: | ||
In a browser: | ||
~~~ html | ||
```html | ||
<script src="platform.js"></script> | ||
~~~ | ||
``` | ||
Via [npm](http://npmjs.org/): | ||
~~~ bash | ||
```bash | ||
npm install platform | ||
~~~ | ||
``` | ||
In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/): | ||
~~~ js | ||
```js | ||
var platform = require('platform'); | ||
~~~ | ||
``` | ||
In [Rhino](http://www.mozilla.org/rhino/): | ||
~~~ js | ||
```js | ||
load('platform.js'); | ||
~~~ | ||
``` | ||
In an AMD loader like [RequireJS](http://requirejs.org/): | ||
~~~ js | ||
```js | ||
require({ | ||
@@ -63,7 +64,7 @@ 'paths': { | ||
}); | ||
~~~ | ||
``` | ||
Usage example: | ||
~~~ js | ||
```js | ||
// on IE10 x86 platform preview running in IE7 compatibility mode on Windows 7 64 bit edition | ||
@@ -92,12 +93,14 @@ platform.name; // 'IE' | ||
info.description; // 'Opera 11.52 (identifying as Firefox 4.0) on Mac OS X 10.7.2' | ||
~~~ | ||
``` | ||
## Author | ||
* [John-David Dalton](http://allyoucanleet.com/) | ||
[![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | ||
| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | | ||
|---| | ||
| [John-David Dalton](http://allyoucanleet.com/) | | ||
## Contributors | ||
* [Mathias Bynens](http://mathiasbynens.be/) | ||
[![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | ||
| [![twitter/demoneaux](http://gravatar.com/avatar/029b19dba521584d83398ada3ecf6131?s=70)](https://twitter.com/demoneaux "Follow @demoneaux on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | | ||
|---|---| | ||
| [Benjamin Tan](http://d10.github.io/) | [Mathias Bynens](http://mathiasbynens.be/) | |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
102
0
1
1
40092
4
990
1