platform-detect
Advanced tools
Comparing version 2.0.1 to 2.0.2
237
index.js
@@ -1,1 +0,236 @@ | ||
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define("platform-detect",o):e["platform-detect"]=o()}(this,function(){"use strict";function e(e,o){var n=window.matchMedia(e);o(n.matches);var i=()=>o(n.matches);return n.addListener(i),()=>n.removeListener(i)}function o(e,o){a[e]&&a[e].forEach(e=>e(o))}function n(){return t.tv?"tv":t.touch&&s<600?"phone":t.touch&&!t.mouse?"tablet":t.battery?"laptop":"desktop"}var i="undefined"!=typeof navigator&&"undefined"!=typeof window;if(i&&"undefined"!=typeof nw)try{nw.Window.get()}catch(e){i=!1}var t={gui:i,terminal:!i},d=i?navigator.userAgent:void 0;t.node="undefined"!=typeof process&&!!process.versions&&!!process.versions.node,t.pwa=t.gui&&window.matchMedia("(display-mode: standalone)").matches&&null!==document.head.querySelector('[rel="manifest"]'),t.uwp="undefined"!=typeof Windows&&"undefined"!=typeof MSApp,t.nwjs=!(!t.node||!process.versions.nw),t.electron=!(!t.node||!process.versions.electron),t.cordova=!(!t.gui||!window.cordova),t.chromeapp=void 0,t.packaged=t.uwp||t.nwjs||t.electron||t.cordova||t.chromeapp,t.web=!t.node&&!t.packaged,t.website=t.web&&!t.pwa,t.worker=!t.gui&&"undefined"!=typeof self&&void 0!==self.importScripts,t.android=!!t.gui&&d.includes("Android"),t.chromeos=!!t.gui&&d.includes("CrOS"),t.tizen=!!t.gui&&d.includes("Tizen"),t.ios=t.gui&&/iPad|iPhone|iPod/.test(d)&&!window.MSStream||!1,t.linuxBased=t.android||t.tizen,t.windows=t.node?"win32"===process.platform:d.includes("Windows"),t.macos=t.node?"darwin"===process.platform:d.includes("Macintosh"),t.linux=t.node?"linux"===process.platform:d.includes("Linux")&&!t.linuxBased&&!t.macos,t.edge=t.gui&&d.includes("Edge/"),t.chrome=t.gui&&d.includes("Chrome")&&!t.edge,t.safari=t.gui&&d.includes("Safari")&&!t.chrome&&!t.edge,t.opera=t.gui&&d.includes("Opera"),t.firefox=t.gui&&d.includes("Firefox"),t.edgeHtml=t.edge,t.blink=t.chrome,t.webkit=t.blink||t.safari,t.gecko=t.firefox;var a={};if(t.on=function(e,o){a[e]=a[e]||new Set,a[e].add(o)},t.removeListener=function(e,o){a[e]&&a[e].delete(o)},t.gui)if(t.pixelRatio=parseFloat(window.devicePixelRatio.toFixed(2)),t.gameconsole=d.includes("Xbox")||d.includes("PlayStation"),t.gameconsole)t.gamepad=!0,t.mouse=!0,t.touch=!1,t.tv=!0,t.battery=!1,t.phone=t.tablet=t.hybrid=t.laptop=t.desktop=!1,t.gamepads=0,window.addEventListener("gamepadconnected",e=>t.gamepads++),window.addEventListener("gamepaddisconnected",e=>t.gamepads--);else{t.touch=navigator.maxTouchPoints>0,t.tv=d.includes("TV");var r=navigator.getGamepads();t.gamepad=!!r&&Array.from(r).some(e=>null!==e),e("(orientation: portrait)",e=>{t.portrait=e;t.landscape=!e;t.orientation=e?"portrait":"landscape";o("portrait",t.portrait);o("landscape",t.landscape);o("orientation",t.orientation)}),e("(any-pointer: coarse)",e=>{t.touch=e;o("touch",t.touch)}),e("(hover: hover)",e=>{t.mouse=e;t.input=e?"mouse":"touch";t.formFactor=n();o("mouse",t.mouse);o("input",t.input);o("formFactor",t.formFactor)});var s=Math.min(window.screen.width,window.screen.height)}if(t.csp=t.uwp||t.chromeapp||!1,t.nwjs)t.dev="sdk"===process.versions["nw-flavor"];else if(t.electron)t.dev=process.execPath.replace(/\\/g,"/").includes("node_modules/electron/");else if(t.uwp)t.dev=Windows.ApplicationModel.Package.current.isDevelopmentMode;else if(t.web){let e=/./;e.toString=(()=>t.dev=!0),console.log("%c",e)}else t.node?t.dev="production"!==process.env.NODE_ENV:t.dev=!1;return t}); | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define('platform-detect', factory) : | ||
(global['platform-detect'] = factory()); | ||
}(this, (function () { 'use strict'; | ||
// The app has a window to render DOM content in. | ||
var gui = typeof navigator !== 'undefined' && typeof window !== 'undefined'; | ||
// NW.JS' background script loads into invisible empty HTML page. | ||
// Therefore NW.JS "main" script has all of window, document, navigator objects | ||
// and window.open() won't be null if App's window is launched from such "main". | ||
if (gui && typeof nw !== 'undefined') { | ||
try { | ||
nw.Window.get(); | ||
} catch(err) { | ||
gui = false; | ||
} | ||
} | ||
// The app runs in terminal/console and can only use console.log. | ||
var terminal = !gui; | ||
var ua = gui ? navigator.userAgent : undefined; | ||
function registerQuery(query, handler) { | ||
var mql = window.matchMedia(query); | ||
handler(mql.matches); | ||
var listener = () => handler(mql.matches); | ||
mql.addListener(listener); | ||
return () => mql.removeListener(listener) | ||
} | ||
// The holy grail | ||
var p = {gui, terminal, registerQuery}; | ||
// Fully functional Node & core modules. | ||
// it is true for Node.js, Electron, NW.JS | ||
// it is false for browsers with shims or bundles of some Node modules (shimmed process, EventEmitter, etc..) | ||
p.node = typeof process !== 'undefined' | ||
&& !!process.versions | ||
&& !!process.versions.node; | ||
// Detects if the APP is launched as standalone Progressive Web App. Still a website, but looking like OS app, without url bar. | ||
// TODO: WARNING: this returns true even for popup windows created with window.open() | ||
p.pwa = p.gui | ||
&& window.matchMedia('(display-mode: standalone)').matches | ||
&& (document.head.querySelector('[rel="manifest"]') !== null); | ||
// Windows 10 app - Universal Windows Platform. | ||
p.uwp = typeof Windows !== 'undefined' && typeof MSApp !== 'undefined'; | ||
// Node + Chromium | ||
p.nwjs = !!(p.node && process.versions.nw); | ||
p.electron = !!(p.node && process.versions.electron); | ||
// Cordova mobile app | ||
p.cordova = !!(p.gui && window.cordova); | ||
// Chrome app (Chrome OS app) | ||
p.chromeapp = undefined; // todo | ||
// The platform requires app to be compiled, bundled or packaged. | ||
p.packaged = p.uwp || p.nwjs || p.electron || p.cordova || p.chromeapp; | ||
// The app runs inside browser and is served from a server or browser cache. | ||
p.web = !p.node && !p.packaged; | ||
// App is a plain old webpage and not a PWA. | ||
p.website = p.web && !p.pwa; | ||
// Script is executed inside Web Worker | ||
p.worker = !p.gui | ||
&& typeof self !== 'undefined' | ||
&& self.importScripts !== undefined; | ||
//&& self.close !== undefined | ||
//p.serviceWorker = p.worker && !!navigator.serviceWorker.controller | ||
// TODO: test user agent availability in worker | ||
// TODO: figure out if these should be mutually exclusive (Tizen and Android are based on linux and have Linux in their user agents) | ||
p.android = p.gui ? ua.includes('Android') : false; // TODO | ||
p.chromeos = p.gui ? ua.includes('CrOS') : false; // TODO | ||
p.tizen = p.gui ? ua.includes('Tizen') : false; // TODO | ||
p.ios = p.gui && /iPad|iPhone|iPod/.test(ua) && !window.MSStream || false; | ||
p.linuxBased = p.android || p.tizen; | ||
p.windows = p.node ? process.platform === 'win32' : ua.includes('Windows'); | ||
p.macos = p.node ? process.platform === 'darwin' : ua.includes('Macintosh'); | ||
p.linux = p.node ? process.platform === 'linux' : ua.includes('Linux') && !p.linuxBased && !p.macos; | ||
// These return true if their rendering engine is used to render the app. | ||
// I.e: UWP apps are rendered by Edge's EdgeHTML, Electron/NWJS apps are rendered by Chromium. | ||
// https://blogs.windows.com/msedgedev/2017/10/05/microsoft-edge-ios-android-developer/#49Fi4TfpgzHAwuXQ.97 | ||
//p.edgeAndroid = p.gui && ua.includes('EdgiOS/') | ||
//p.edgeIos = p.gui && ua.includes('EdgA/') | ||
//p.edgeWin = p.gui && ua.includes('Edge/') | ||
//p.edge = edgeWin | ||
// NOTE: Only returnin true for Edge (EdgeHtml) on windows. Android/iOs versions of Edge are powered by Webkit. | ||
p.edge = p.gui && ua.includes('Edge/'); | ||
p.chrome = p.gui && ua.includes('Chrome') && !p.edge; | ||
p.safari = p.gui && ua.includes('Safari') && !p.chrome && !p.edge; | ||
p.opera = p.gui && ua.includes('Opera'); | ||
p.firefox = p.gui && ua.includes('Firefox'); | ||
// RENDERING & JS ENGINES | ||
// TODO: all other android/ios browsers are webkit based. | ||
p.edgeHtml = p.edge; | ||
p.blink = p.chrome;// || edgeAndroid | ||
p.webkit = p.blink || p.safari;// || edgeIos | ||
p.gecko = p.firefox; | ||
// minimal EventEmitter like API for notifying abou changes | ||
var listeners = {}; | ||
p.on = function(name, listener) { | ||
listeners[name] = listeners[name] || new Set; | ||
listeners[name].add(listener); | ||
}; | ||
p.removeListener = function(name, listener) { | ||
if (listeners[name]) | ||
listeners[name].delete(listener); | ||
}; | ||
function emit(name, value) { | ||
if (listeners[name]) | ||
listeners[name].forEach(listener => listener(value)); | ||
} | ||
if (p.gui) { | ||
p.pixelRatio = parseFloat(window.devicePixelRatio.toFixed(2)); | ||
p.gameconsole = ua.includes('Xbox') || ua.includes('PlayStation'); | ||
if (p.gameconsole) { | ||
// WARNING: do not use Gamepad API unless necessary. On Xbox it automatically hides pointer and shows warning that the site uses | ||
// custom gamepad controls. We don't want to trigger that. This library only observes. | ||
p.gamepad = true; | ||
p.mouse = true; // this is controvertial. if app decides to use gamepad controls, then it doesnt have the mouse & hover anymore | ||
p.touch = false; | ||
p.tv = true; | ||
p.battery = false; | ||
p.phone = p.tablet = p.hybrid = p.laptop = p.desktop = false; | ||
// undocumented api used for detecting current use of the site | ||
p.gamepads = 0; | ||
window.addEventListener('gamepadconnected', e => p.gamepads++); | ||
window.addEventListener('gamepaddisconnected', e => p.gamepads--); | ||
} else { | ||
p.touch = navigator.maxTouchPoints > 0; | ||
p.tv = ua.includes('TV'); | ||
// TODO: detect when gamepad is custom handled (and used not just used to control the emulated pointer on smart TVs) | ||
// TODO: throw gamepad into the platform.input | ||
var gamepads = navigator.getGamepads(); | ||
p.gamepad = !!gamepads && Array.from(gamepads).some(g => g !== null); | ||
registerQuery('(orientation: portrait)', bool => { | ||
p.portrait = bool; | ||
p.landscape = !bool; | ||
p.orientation = bool ? 'portrait' : 'landscape'; | ||
emit('portrait', p.portrait); | ||
emit('landscape', p.landscape); | ||
emit('orientation', p.orientation); | ||
}); | ||
registerQuery('(any-pointer: coarse)', bool => { | ||
p.touch = bool; | ||
emit('touch', p.touch); | ||
}); | ||
registerQuery('(hover: hover)', bool => { | ||
p.mouse = bool; | ||
p.input = bool ? 'mouse' : 'touch'; | ||
p.formfactor = getFormfactor(); | ||
emit('mouse', p.mouse); | ||
emit('input', p.input); | ||
emit('formfactor', p.formfactor); | ||
}); | ||
// TODO: apply some light transpilation with babel because my relatively new smart tv runs tizen | ||
// with 2 years old chromium which doesn't support destructuring syntax. | ||
function getFormfactor() { | ||
var shorterScreenSide = Math.min(window.screen.width, window.screen.height); | ||
// TODO: add 'iot' or some other form of window-less app or monitor-less hardware. | ||
if (p.tv) | ||
return 'tv' | ||
else if (p.touch && shorterScreenSide < 600) | ||
return 'phone' | ||
else if (p.touch && !p.mouse) | ||
return 'tablet' | ||
//else if (p.touch && p.mouse) | ||
// return 'hybrid' | ||
else if (p.battery) | ||
return 'laptop' | ||
else | ||
return 'desktop' | ||
} | ||
} | ||
} | ||
// Detects if the platform is constrained by Cancerous Security Policy. | ||
p.csp = p.uwp || p.chromeapp || false; | ||
if (p.nwjs) { | ||
p.dev = process.versions['nw-flavor'] === 'sdk'; | ||
} else if (p.electron) { | ||
p.dev = process.execPath.replace(/\\/g, '/').includes('node_modules/electron/'); | ||
} else if (p.uwp) { | ||
p.dev = Windows.ApplicationModel.Package.current.isDevelopmentMode; | ||
} else if (p.web) { | ||
// toString on object is only called in developer tools in console. | ||
// NOTE: Printing extra empty line into console is not ideal but it's the only reliable way. | ||
// Window size checking seemed to be somewhat reliable but was failing on Tizen smart TV in the end. | ||
let temp = /./; | ||
temp.toString = () => p.dev = true; | ||
console.log('%c', temp); | ||
// TODO: doesnt work anymore in latest chrome | ||
} else if (p.node) { | ||
p.dev = process.env.NODE_ENV !== 'production'; | ||
} else { | ||
// Detects if NW.JS runs in SDK version (console available) and if Electron is executed from npm/node_modules/electron global. | ||
// TODO: would be nice to detect if UWP is attached to Visual Studio debugger. | ||
p.dev = false; | ||
} | ||
return p; | ||
}))); |
{ | ||
"name": "platform-detect", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "🃏 Minimalistic isomorphic library for detection of platform, runtime, APIs and more.", | ||
@@ -5,0 +5,0 @@ "author": "Mike Kovarik", |
@@ -40,2 +40,4 @@ # platform-detect | ||
Minified bundle is also available at [unpkg.com/platform-detect](https://unpkg.com/platform-detect) | ||
## Usage | ||
@@ -73,5 +75,5 @@ | ||
import {chrome, edge, safari} from 'platform-detect/browser.mjs' | ||
import {input, mouse, touch, formFactor} from 'platform-detect/formfactor.mjs' | ||
import {input, mouse, touch, formfactor} from 'platform-detect/formfactor.mjs' | ||
if (formFactor === 'tv' && tizen) { | ||
if (formfactor === 'tv' && tizen) { | ||
console.log(`I'm a Samsung Smart TV!`) | ||
@@ -156,3 +158,3 @@ } | ||
* **`landscape`** bool, event | ||
* **`formFactor`** string, event | ||
* **`formfactor`** string, event | ||
<br>values: `phone`, `tablet`, `desktop` or `tv` | ||
@@ -159,0 +161,0 @@ * **`pixelRatio`** float |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
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
27586
392
217