quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
356 lines (313 loc) • 9.47 kB
JavaScript
/* eslint-disable no-useless-escape */
/* eslint-disable no-unused-expressions */
/* eslint-disable no-mixed-operators */
import Vue from 'vue'
export const isSSR = typeof window === 'undefined'
export let fromSSR = false
export let onSSR = isSSR
export let iosEmulated = false
export let iosCorrection
function getMatch (userAgent, platformMatch) {
const match = /(edge|edga|edgios)\/([\w.]+)/.exec(userAgent) ||
/(opr)[\/]([\w.]+)/.exec(userAgent) ||
/(vivaldi)[\/]([\w.]+)/.exec(userAgent) ||
/(chrome|crios)[\/]([\w.]+)/.exec(userAgent) ||
/(iemobile)[\/]([\w.]+)/.exec(userAgent) ||
/(version)(applewebkit)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent) ||
/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent) ||
/(firefox|fxios)[\/]([\w.]+)/.exec(userAgent) ||
/(webkit)[\/]([\w.]+)/.exec(userAgent) ||
/(opera)(?:.*version|)[\/]([\w.]+)/.exec(userAgent) ||
/(msie) ([\w.]+)/.exec(userAgent) ||
(userAgent.indexOf('trident') >= 0 && /(rv)(?::| )([\w.]+)/.exec(userAgent)) ||
(userAgent.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(userAgent)) ||
[]
return {
browser: match[5] || match[3] || match[1] || '',
version: match[2] || match[4] || '0',
versionNumber: match[4] || match[2] || '0',
platform: platformMatch[0] || ''
}
}
function getPlatformMatch (userAgent) {
return /(ipad)/.exec(userAgent) ||
/(ipod)/.exec(userAgent) ||
/(windows phone)/.exec(userAgent) ||
/(iphone)/.exec(userAgent) ||
/(kindle)/.exec(userAgent) ||
/(silk)/.exec(userAgent) ||
/(android)/.exec(userAgent) ||
/(win)/.exec(userAgent) ||
/(mac)/.exec(userAgent) ||
/(linux)/.exec(userAgent) ||
/(cros)/.exec(userAgent) ||
/(playbook)/.exec(userAgent) ||
/(bb)/.exec(userAgent) ||
/(blackberry)/.exec(userAgent) ||
[]
}
const hasTouch = isSSR === false
? 'ontouchstart' in window || window.navigator.maxTouchPoints > 0
: false
function applyIosCorrection (is) {
iosCorrection = { is: { ...is } }
delete is.mac
delete is.desktop
const platform = Math.min(window.innerHeight, window.innerWidth) > 414
? 'ipad'
: 'iphone'
Object.assign(is, {
mobile: true,
ios: true,
platform,
[ platform ]: true
})
}
function getPlatform (UA) {
const
userAgent = UA.toLowerCase(),
platformMatch = getPlatformMatch(userAgent),
matched = getMatch(userAgent, platformMatch),
browser = {}
if (matched.browser) {
browser[matched.browser] = true
browser.version = matched.version
browser.versionNumber = parseInt(matched.versionNumber, 10)
}
if (matched.platform) {
browser[matched.platform] = true
}
const knownMobiles = browser.android ||
browser.ios ||
browser.bb ||
browser.blackberry ||
browser.ipad ||
browser.iphone ||
browser.ipod ||
browser.kindle ||
browser.playbook ||
browser.silk ||
browser['windows phone']
// These are all considered mobile platforms, meaning they run a mobile browser
if (knownMobiles === true || userAgent.indexOf('mobile') > -1) {
browser.mobile = true
if (browser.edga || browser.edgios) {
browser.edge = true
matched.browser = 'edge'
}
else if (browser.crios) {
browser.chrome = true
matched.browser = 'chrome'
}
else if (browser.fxios) {
browser.firefox = true
matched.browser = 'firefox'
}
}
// If it's not mobile we should consider it's desktop platform, meaning it runs a desktop browser
// It's a workaround for anonymized user agents
// (browser.cros || browser.mac || browser.linux || browser.win)
else {
browser.desktop = true
}
// Set iOS if on iPod, iPad or iPhone
if (browser.ipod || browser.ipad || browser.iphone) {
browser.ios = true
}
if (browser['windows phone']) {
browser.winphone = true
delete browser['windows phone']
}
// Chrome, Opera 15+, Vivaldi and Safari are webkit based browsers
if (
browser.chrome ||
browser.opr ||
browser.safari ||
browser.vivaldi ||
// we expect unknown, non iOS mobile browsers to be webkit based
(
browser.mobile === true &&
browser.ios !== true &&
knownMobiles !== true
)
) {
browser.webkit = true
}
// IE11 has a new token so we will assign it msie to avoid breaking changes
if (browser.rv || browser.iemobile) {
matched.browser = 'ie'
browser.ie = true
}
// Blackberry browsers are marked as Safari on BlackBerry
if (browser.safari && browser.blackberry || browser.bb) {
matched.browser = 'blackberry'
browser.blackberry = true
}
// Playbook browsers are marked as Safari on Playbook
if (browser.safari && browser.playbook) {
matched.browser = 'playbook'
browser.playbook = true
}
// Opera 15+ are identified as opr
if (browser.opr) {
matched.browser = 'opera'
browser.opera = true
}
// Stock Android browsers are marked as Safari on Android.
if (browser.safari && browser.android) {
matched.browser = 'android'
browser.android = true
}
// Kindle browsers are marked as Safari on Kindle
if (browser.safari && browser.kindle) {
matched.browser = 'kindle'
browser.kindle = true
}
// Kindle Silk browsers are marked as Safari on Kindle
if (browser.safari && browser.silk) {
matched.browser = 'silk'
browser.silk = true
}
if (browser.vivaldi) {
matched.browser = 'vivaldi'
browser.vivaldi = true
}
// Assign the name and platform variable
browser.name = matched.browser
browser.platform = matched.platform
if (isSSR === false) {
if (userAgent.indexOf('electron') > -1) {
browser.electron = true
}
else if (document.location.href.indexOf('-extension://') > -1) {
browser.bex = true
}
else {
if (window.Capacitor !== void 0) {
browser.capacitor = true
browser.nativeMobile = true
browser.nativeMobileWrapper = 'capacitor'
}
else if (window._cordovaNative !== void 0 || window.cordova !== void 0) {
browser.cordova = true
browser.nativeMobile = true
browser.nativeMobileWrapper = 'cordova'
}
if (
hasTouch === true &&
browser.mac === true &&
(
(browser.desktop === true && browser.safari === true) ||
(
browser.nativeMobile === true &&
browser.android !== true &&
browser.ios !== true &&
browser.ipad !== true
)
)
) {
/*
* Correction needed for iOS since the default
* setting on iPad is to request desktop view; if we have
* touch support and the user agent says it's a
* desktop, we infer that it's an iPhone/iPad with desktop view
* so we must fix the false positives
*/
applyIosCorrection(browser)
}
}
fromSSR = browser.nativeMobile === void 0 &&
browser.electron === void 0 &&
document.querySelector('[data-server-rendered]') !== null
if (fromSSR === true) {
onSSR = true
}
}
return browser
}
const userAgent = isSSR !== true
? navigator.userAgent || navigator.vendor || window.opera
: ''
const ssrClient = {
has: {
touch: false,
webStorage: false
},
within: { iframe: false }
}
// We export "client" for hydration error-free parts,
// like touch directives who do not (and must NOT) wait
// for the client takeover;
// Do NOT import this directly in your app, unless you really know
// what you are doing.
export const client = isSSR === false
? {
userAgent,
is: getPlatform(userAgent),
has: {
touch: hasTouch,
webStorage: (() => {
try {
if (window.localStorage) {
return true
}
}
catch (e) {}
return false
})()
},
within: {
iframe: window.self !== window.top
}
}
: ssrClient
const Platform = {
install ($q, queues) {
if (isSSR === true) {
// we're on server-side, so we push
// to the server queue instead of
// applying directly
queues.server.push((q, ctx) => {
q.platform = this.parseSSR(ctx.ssr)
})
}
else if (fromSSR === true) {
// must match with server-side before
// client taking over in order to prevent
// hydration errors
Object.assign(this, client, iosCorrection, ssrClient)
// takeover should increase accuracy for
// the rest of the props; we also avoid
// hydration errors
queues.takeover.push(q => {
onSSR = fromSSR = false
Object.assign(q.platform, client)
iosCorrection = void 0
})
// we need to make platform reactive
// for the takeover phase
Vue.util.defineReactive($q, 'platform', this)
}
else {
// we don't have any business with SSR, so
// directly applying...
Object.assign(this, client)
$q.platform = this
}
}
}
if (isSSR === true) {
Platform.parseSSR = (/* ssrContext */ ssr) => {
const userAgent = ssr.req.headers['user-agent'] || ssr.req.headers['User-Agent'] || ''
return {
...client,
userAgent,
is: getPlatform(userAgent)
}
}
}
else {
iosEmulated = client.is.ios === true &&
window.navigator.vendor.toLowerCase().indexOf('apple') === -1
}
export default Platform