1
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
github: juliangruber
|
||||
patreon: juliangruber
|
||||
custom: "https://paypal.me/julianpetergruber"
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "node"
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
|
||||
# is-mobile
|
||||
|
||||
Check if mobile browser, based on useragent string.
|
||||
|
||||
[](https://travis-ci.org/juliangruber/is-mobile)
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
var mobile = require('is-mobile');
|
||||
|
||||
console.log(mobile());
|
||||
// => false
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### mobile({ [ua], [tablet], [featureDetect] })
|
||||
|
||||
Returns true if a mobile browser is being used.
|
||||
|
||||
If you don't specify `opts.ua` it will use `navigator.userAgent`.
|
||||
|
||||
To add support for tablets, set `tablet: true`.
|
||||
|
||||
To enable feature detection (i.e. namely for iPad with iOS 13), set `featureDetect: true` and `tablet: true`. This will only work in browser environments.
|
||||
|
||||
`opts.ua` can also be an instance of a [node.js http request](http://nodejs.org/api/http.html#http_http_incomingmessage), in which
|
||||
case it will read the user agent header.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var http = require('http');
|
||||
var mobile = require('is-mobile');
|
||||
|
||||
var server = http.createServer(function (req, res) {
|
||||
res.end(mobile({ ua: req }));
|
||||
});
|
||||
|
||||
server.listen(8000);
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://npmjs.org) do:
|
||||
|
||||
```bash
|
||||
npm install is-mobile
|
||||
```
|
||||
|
||||
Bundle for the browser with
|
||||
[browserify](https://github.com/substack/node-browserify).
|
||||
|
||||
## Kudos
|
||||
|
||||
Taken from [detectmobilebrowsers.com](http://detectmobilebrowsers.com/).
|
||||
|
||||
Armv7l support added by [@antongolub](https://github.com/antongolub).
|
||||
|
||||
## License
|
||||
|
||||
(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
interface HttpRequestHeadersInterfaceMock {
|
||||
[id: string]: string | string[] | undefined
|
||||
}
|
||||
|
||||
interface HttpRequestInterfaceMock {
|
||||
headers: HttpRequestHeadersInterfaceMock,
|
||||
|
||||
[id: string]: any,
|
||||
}
|
||||
|
||||
export interface IsMobileOptions
|
||||
{
|
||||
ua?: string | HttpRequestInterfaceMock
|
||||
tablet?: boolean
|
||||
featureDetect?: boolean
|
||||
}
|
||||
|
||||
export declare function isMobile(opts?:IsMobileOptions): boolean;
|
||||
export default isMobile;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = isMobile
|
||||
module.exports.isMobile = isMobile
|
||||
module.exports.default = isMobile
|
||||
|
||||
const mobileRE = /(android|bb\d+|meego).+mobile|armv7l|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|redmi|series[46]0|samsungbrowser.*mobile|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i
|
||||
const notMobileRE = /CrOS/
|
||||
|
||||
const tabletRE = /android|ipad|playbook|silk/i
|
||||
|
||||
function isMobile (opts) {
|
||||
if (!opts) opts = {}
|
||||
let ua = opts.ua
|
||||
if (!ua && typeof navigator !== 'undefined') ua = navigator.userAgent
|
||||
if (ua && ua.headers && typeof ua.headers['user-agent'] === 'string') {
|
||||
ua = ua.headers['user-agent']
|
||||
}
|
||||
if (typeof ua !== 'string') return false
|
||||
|
||||
let result =
|
||||
(mobileRE.test(ua) && !notMobileRE.test(ua)) ||
|
||||
(!!opts.tablet && tabletRE.test(ua))
|
||||
|
||||
if (
|
||||
!result &&
|
||||
opts.tablet &&
|
||||
opts.featureDetect &&
|
||||
navigator &&
|
||||
navigator.maxTouchPoints > 1 &&
|
||||
ua.indexOf('Macintosh') !== -1 &&
|
||||
ua.indexOf('Safari') !== -1
|
||||
) {
|
||||
result = true
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "is-mobile",
|
||||
"description": "Check if mobile browser.",
|
||||
"version": "5.0.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/juliangruber/is-mobile.git"
|
||||
},
|
||||
"homepage": "https://github.com/juliangruber/is-mobile",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"release": "np",
|
||||
"test": "prettier-standard '**/*.js' && standard && npm run test:unit",
|
||||
"test:unit": "node--test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"np": "^8.0.4",
|
||||
"prettier-standard": "^16.4.1",
|
||||
"standard": "^16.0.4",
|
||||
"test": "^3.0.0",
|
||||
"user-agents": "^1.0.845"
|
||||
},
|
||||
"keywords": [
|
||||
"mobile",
|
||||
"desktop",
|
||||
"check",
|
||||
"browser"
|
||||
],
|
||||
"author": {
|
||||
"name": "Julian Gruber",
|
||||
"email": "julian@juliangruber.com",
|
||||
"url": "http://juliangruber.com"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
# https://tea.xyz/what-is-this-file
|
||||
---
|
||||
version: 1.0.0
|
||||
codeOwners:
|
||||
- '0xE7DEE1B8Bb97C3065850Cf582D6DED57C6009587'
|
||||
quorum: 1
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('assert')
|
||||
const test = require('test')
|
||||
const UserAgent = require('user-agents')
|
||||
const isMobile = require('./')
|
||||
|
||||
const iphone =
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3'
|
||||
const chrome =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36'
|
||||
const ffos = 'Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0'
|
||||
const ipad =
|
||||
'Mozilla/5.0 (iPad; CPU OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13F69 Safari/601.1'
|
||||
const ios13ipad =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
||||
const ios13ipadpro =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15'
|
||||
const samsung =
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/16.0 Chrome/92.0.4515.166 Safari/537.36'
|
||||
const samsungMobile =
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/16.0 Chrome/92.0.4515.166 Mobile Safari/537.36'
|
||||
const chromeOS =
|
||||
'Mozilla/5.0 (X11; CrOS armv7l 12105.100.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.144 Safari/537.36'
|
||||
const redmiMobile =
|
||||
'HashKey/1.20.0 (Redmi K30; Android ) Language/zh Theme/light ScreenWidth/392 ScreenHeight/856'
|
||||
|
||||
test('is mobile', function () {
|
||||
assert(isMobile({ ua: iphone }))
|
||||
assert(isMobile({ ua: ffos }))
|
||||
assert(!isMobile({ ua: ipad }))
|
||||
assert(isMobile({ ua: ipad, tablet: true }))
|
||||
assert(isMobile({ ua: { headers: { 'user-agent': iphone } } }))
|
||||
assert(!isMobile({ ua: chrome }))
|
||||
assert(!isMobile({ ua: { headers: { 'user-agent': chrome } } }))
|
||||
assert(!isMobile())
|
||||
assert(!isMobile({ ua: { headers: null } }))
|
||||
assert(!isMobile({ ua: { headers: { 'user-agent': null } } }))
|
||||
assert(!isMobile({ ua: samsung }))
|
||||
assert(isMobile({ ua: samsungMobile }))
|
||||
assert(isMobile({ ua: redmiMobile }))
|
||||
assert(!isMobile(chromeOS))
|
||||
assert(!isMobile(chromeOS, { tablet: true }))
|
||||
|
||||
global.navigator = {}
|
||||
|
||||
global.navigator.userAgent = iphone
|
||||
assert(isMobile())
|
||||
assert(isMobile({ tablet: true }))
|
||||
|
||||
global.navigator.userAgent = chrome
|
||||
assert(!isMobile())
|
||||
assert(!isMobile({ tablet: true }))
|
||||
|
||||
global.navigator.userAgent = ipad
|
||||
assert(!isMobile())
|
||||
assert(isMobile({ tablet: true }))
|
||||
|
||||
global.navigator = { maxTouchPoints: 5 }
|
||||
assert(isMobile({ ua: ios13ipad, tablet: true, featureDetect: true }))
|
||||
assert(isMobile({ ua: ios13ipadpro, tablet: true, featureDetect: true }))
|
||||
})
|
||||
|
||||
test('ua-bruteforce', function () {
|
||||
const limit = 300
|
||||
const checks = [
|
||||
{ deviceCategory: 'mobile', result: true },
|
||||
{ deviceCategory: 'tablet', result: true, tablet: true },
|
||||
{ deviceCategory: 'desktop', result: false }
|
||||
]
|
||||
const testCases = checks.reduce(
|
||||
(cases, { deviceCategory, result, tablet }) => {
|
||||
// The same user-agent string belongs to both `desktop` and `mobile` type entries. No chance to detect `deviceType` properly.
|
||||
// https://github.com/intoli/user-agents/blob/867e318bc00880ae00437e5e8efaa8e5e7ac0696/src/user-agents.json.gz
|
||||
// user-agents v1.0.843
|
||||
const exclude =
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
|
||||
const ua = new UserAgent([
|
||||
({ userAgent }) => userAgent !== exclude,
|
||||
{ deviceCategory }
|
||||
])
|
||||
|
||||
return [
|
||||
...cases,
|
||||
...new Array(limit).fill().map(() => ({
|
||||
ua: ua.random().toString(),
|
||||
result,
|
||||
tablet
|
||||
}))
|
||||
]
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
testCases.forEach(({ ua, result, tablet }) => {
|
||||
test(ua, () => {
|
||||
assert.strictEqual(isMobile({ ua, tablet }), result)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user