UNPKG

vue

Version:

Reactive, component-oriented view layer for modern web interfaces.

147 lines (134 loc) 4.4 kB
/* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto__? export const hasProto = '__proto__' in {} // Browser environment sniffing export const inBrowser = typeof window !== 'undefined' export const UA = inBrowser && window.navigator.userAgent.toLowerCase() export const isIE = UA && /msie|trident/.test(UA) export const isIE9 = UA && UA.indexOf('msie 9.0') > 0 export const isEdge = UA && UA.indexOf('edge/') > 0 export const isAndroid = UA && UA.indexOf('android') > 0 export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA) // this needs to be lazy-evaled because vue may be required before // vue-server-renderer can set VUE_ENV let _isServer export const isServerRendering = () => { if (_isServer === undefined) { /* istanbul ignore if */ if (!inBrowser && typeof global !== 'undefined') { // detect presence of vue-server-renderer and avoid // Webpack shimming the process _isServer = global['process'].env.VUE_ENV === 'server' } else { _isServer = false } } return _isServer } // detect devtools export const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__ /* istanbul ignore next */ function isNative (Ctor: Function): boolean { return /native code/.test(Ctor.toString()) } /** * Defer a task to execute it asynchronously. */ export const nextTick = (function () { const callbacks = [] let pending = false let timerFunc function nextTickHandler () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native Promise.then or MutationObserver. // MutationObserver has wider support, however it is seriously bugged in // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It // completely stops working after triggering a few times... so, if native // Promise is available, we will use it: /* istanbul ignore if */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // in problematic UIWebViews, Promise.then doesn't completely break, but // it can get stuck in a weird state where callbacks are pushed into the // microtask queue but the queue isn't being flushed, until the browser // needs to do some other work, e.g. handle a timer. Therefore we can // "force" the microtask queue to be flushed by adding an empty timer. if (isIOS) setTimeout(noop) } } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS IE11, iOS7, Android 4.4 var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => { if (cb) cb.call(ctx) if (_resolve) _resolve(ctx) }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } } })() let _Set /* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) { // use native Set when available. _Set = Set } else { // a non-standard Set polyfill that only works with primitive keys. _Set = class Set { set: Object; constructor () { this.set = Object.create(null) } has (key: string | number) { return this.set[key] === true } add (key: string | number) { this.set[key] = true } clear () { this.set = Object.create(null) } } } export { _Set }