diff options
Diffstat (limited to 'node_modules/vue/src/platforms/web/runtime/transition-util.js')
| -rw-r--r-- | node_modules/vue/src/platforms/web/runtime/transition-util.js | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/node_modules/vue/src/platforms/web/runtime/transition-util.js b/node_modules/vue/src/platforms/web/runtime/transition-util.js new file mode 100644 index 00000000..47668f0c --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/transition-util.js @@ -0,0 +1,185 @@ +/* @flow */ + +import { inBrowser, isIE9 } from 'core/util/index' +import { addClass, removeClass } from './class-util' +import { remove, extend, cached } from 'shared/util' + +export function resolveTransition (def?: string | Object): ?Object { + if (!def) { + return + } + /* istanbul ignore else */ + if (typeof def === 'object') { + const res = {} + if (def.css !== false) { + extend(res, autoCssTransition(def.name || 'v')) + } + extend(res, def) + return res + } else if (typeof def === 'string') { + return autoCssTransition(def) + } +} + +const autoCssTransition: (name: string) => Object = cached(name => { + return { + enterClass: `${name}-enter`, + enterToClass: `${name}-enter-to`, + enterActiveClass: `${name}-enter-active`, + leaveClass: `${name}-leave`, + leaveToClass: `${name}-leave-to`, + leaveActiveClass: `${name}-leave-active` + } +}) + +export const hasTransition = inBrowser && !isIE9 +const TRANSITION = 'transition' +const ANIMATION = 'animation' + +// Transition property/event sniffing +export let transitionProp = 'transition' +export let transitionEndEvent = 'transitionend' +export let animationProp = 'animation' +export let animationEndEvent = 'animationend' +if (hasTransition) { + /* istanbul ignore if */ + if (window.ontransitionend === undefined && + window.onwebkittransitionend !== undefined + ) { + transitionProp = 'WebkitTransition' + transitionEndEvent = 'webkitTransitionEnd' + } + if (window.onanimationend === undefined && + window.onwebkitanimationend !== undefined + ) { + animationProp = 'WebkitAnimation' + animationEndEvent = 'webkitAnimationEnd' + } +} + +// binding to window is necessary to make hot reload work in IE in strict mode +const raf = inBrowser + ? window.requestAnimationFrame + ? window.requestAnimationFrame.bind(window) + : setTimeout + : /* istanbul ignore next */ fn => fn() + +export function nextFrame (fn: Function) { + raf(() => { + raf(fn) + }) +} + +export function addTransitionClass (el: any, cls: string) { + const transitionClasses = el._transitionClasses || (el._transitionClasses = []) + if (transitionClasses.indexOf(cls) < 0) { + transitionClasses.push(cls) + addClass(el, cls) + } +} + +export function removeTransitionClass (el: any, cls: string) { + if (el._transitionClasses) { + remove(el._transitionClasses, cls) + } + removeClass(el, cls) +} + +export function whenTransitionEnds ( + el: Element, + expectedType: ?string, + cb: Function +) { + const { type, timeout, propCount } = getTransitionInfo(el, expectedType) + if (!type) return cb() + const event: string = type === TRANSITION ? transitionEndEvent : animationEndEvent + let ended = 0 + const end = () => { + el.removeEventListener(event, onEnd) + cb() + } + const onEnd = e => { + if (e.target === el) { + if (++ended >= propCount) { + end() + } + } + } + setTimeout(() => { + if (ended < propCount) { + end() + } + }, timeout + 1) + el.addEventListener(event, onEnd) +} + +const transformRE = /\b(transform|all)(,|$)/ + +export function getTransitionInfo (el: Element, expectedType?: ?string): { + type: ?string; + propCount: number; + timeout: number; + hasTransform: boolean; +} { + const styles: any = window.getComputedStyle(el) + const transitionDelays: Array<string> = styles[transitionProp + 'Delay'].split(', ') + const transitionDurations: Array<string> = styles[transitionProp + 'Duration'].split(', ') + const transitionTimeout: number = getTimeout(transitionDelays, transitionDurations) + const animationDelays: Array<string> = styles[animationProp + 'Delay'].split(', ') + const animationDurations: Array<string> = styles[animationProp + 'Duration'].split(', ') + const animationTimeout: number = getTimeout(animationDelays, animationDurations) + + let type: ?string + let timeout = 0 + let propCount = 0 + /* istanbul ignore if */ + if (expectedType === TRANSITION) { + if (transitionTimeout > 0) { + type = TRANSITION + timeout = transitionTimeout + propCount = transitionDurations.length + } + } else if (expectedType === ANIMATION) { + if (animationTimeout > 0) { + type = ANIMATION + timeout = animationTimeout + propCount = animationDurations.length + } + } else { + timeout = Math.max(transitionTimeout, animationTimeout) + type = timeout > 0 + ? transitionTimeout > animationTimeout + ? TRANSITION + : ANIMATION + : null + propCount = type + ? type === TRANSITION + ? transitionDurations.length + : animationDurations.length + : 0 + } + const hasTransform: boolean = + type === TRANSITION && + transformRE.test(styles[transitionProp + 'Property']) + return { + type, + timeout, + propCount, + hasTransform + } +} + +function getTimeout (delays: Array<string>, durations: Array<string>): number { + /* istanbul ignore next */ + while (delays.length < durations.length) { + delays = delays.concat(delays) + } + + return Math.max.apply(null, durations.map((d, i) => { + return toMs(d) + toMs(delays[i]) + })) +} + +function toMs (s: string): number { + return Number(s.slice(0, -1)) * 1000 +} |
