| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 | 
							- /* @flow */
 
- import type Router from '../index'
 
- import { assert } from './warn'
 
- import { getStateKey, setStateKey } from './state-key'
 
- import { extend } from './misc'
 
- const positionStore = Object.create(null)
 
- export function setupScroll () {
 
-   // Prevent browser scroll behavior on History popstate
 
-   if ('scrollRestoration' in window.history) {
 
-     window.history.scrollRestoration = 'manual'
 
-   }
 
-   // Fix for #1585 for Firefox
 
-   // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
 
-   // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
 
-   // window.location.protocol + '//' + window.location.host
 
-   // location.host contains the port and location.hostname doesn't
 
-   const protocolAndPath = window.location.protocol + '//' + window.location.host
 
-   const absolutePath = window.location.href.replace(protocolAndPath, '')
 
-   // preserve existing history state as it could be overriden by the user
 
-   const stateCopy = extend({}, window.history.state)
 
-   stateCopy.key = getStateKey()
 
-   window.history.replaceState(stateCopy, '', absolutePath)
 
-   window.addEventListener('popstate', handlePopState)
 
-   return () => {
 
-     window.removeEventListener('popstate', handlePopState)
 
-   }
 
- }
 
- export function handleScroll (
 
-   router: Router,
 
-   to: Route,
 
-   from: Route,
 
-   isPop: boolean
 
- ) {
 
-   if (!router.app) {
 
-     return
 
-   }
 
-   const behavior = router.options.scrollBehavior
 
-   if (!behavior) {
 
-     return
 
-   }
 
-   if (process.env.NODE_ENV !== 'production') {
 
-     assert(typeof behavior === 'function', `scrollBehavior must be a function`)
 
-   }
 
-   // wait until re-render finishes before scrolling
 
-   router.app.$nextTick(() => {
 
-     const position = getScrollPosition()
 
-     const shouldScroll = behavior.call(
 
-       router,
 
-       to,
 
-       from,
 
-       isPop ? position : null
 
-     )
 
-     if (!shouldScroll) {
 
-       return
 
-     }
 
-     if (typeof shouldScroll.then === 'function') {
 
-       shouldScroll
 
-         .then(shouldScroll => {
 
-           scrollToPosition((shouldScroll: any), position)
 
-         })
 
-         .catch(err => {
 
-           if (process.env.NODE_ENV !== 'production') {
 
-             assert(false, err.toString())
 
-           }
 
-         })
 
-     } else {
 
-       scrollToPosition(shouldScroll, position)
 
-     }
 
-   })
 
- }
 
- export function saveScrollPosition () {
 
-   const key = getStateKey()
 
-   if (key) {
 
-     positionStore[key] = {
 
-       x: window.pageXOffset,
 
-       y: window.pageYOffset
 
-     }
 
-   }
 
- }
 
- function handlePopState (e) {
 
-   saveScrollPosition()
 
-   if (e.state && e.state.key) {
 
-     setStateKey(e.state.key)
 
-   }
 
- }
 
- function getScrollPosition (): ?Object {
 
-   const key = getStateKey()
 
-   if (key) {
 
-     return positionStore[key]
 
-   }
 
- }
 
- function getElementPosition (el: Element, offset: Object): Object {
 
-   const docEl: any = document.documentElement
 
-   const docRect = docEl.getBoundingClientRect()
 
-   const elRect = el.getBoundingClientRect()
 
-   return {
 
-     x: elRect.left - docRect.left - offset.x,
 
-     y: elRect.top - docRect.top - offset.y
 
-   }
 
- }
 
- function isValidPosition (obj: Object): boolean {
 
-   return isNumber(obj.x) || isNumber(obj.y)
 
- }
 
- function normalizePosition (obj: Object): Object {
 
-   return {
 
-     x: isNumber(obj.x) ? obj.x : window.pageXOffset,
 
-     y: isNumber(obj.y) ? obj.y : window.pageYOffset
 
-   }
 
- }
 
- function normalizeOffset (obj: Object): Object {
 
-   return {
 
-     x: isNumber(obj.x) ? obj.x : 0,
 
-     y: isNumber(obj.y) ? obj.y : 0
 
-   }
 
- }
 
- function isNumber (v: any): boolean {
 
-   return typeof v === 'number'
 
- }
 
- const hashStartsWithNumberRE = /^#\d/
 
- function scrollToPosition (shouldScroll, position) {
 
-   const isObject = typeof shouldScroll === 'object'
 
-   if (isObject && typeof shouldScroll.selector === 'string') {
 
-     // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
 
-     // but at the same time, it doesn't make much sense to select an element with an id and an extra selector
 
-     const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
 
-       ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
 
-       : document.querySelector(shouldScroll.selector)
 
-     if (el) {
 
-       let offset =
 
-         shouldScroll.offset && typeof shouldScroll.offset === 'object'
 
-           ? shouldScroll.offset
 
-           : {}
 
-       offset = normalizeOffset(offset)
 
-       position = getElementPosition(el, offset)
 
-     } else if (isValidPosition(shouldScroll)) {
 
-       position = normalizePosition(shouldScroll)
 
-     }
 
-   } else if (isObject && isValidPosition(shouldScroll)) {
 
-     position = normalizePosition(shouldScroll)
 
-   }
 
-   if (position) {
 
-     // $flow-disable-line
 
-     if ('scrollBehavior' in document.documentElement.style) {
 
-       window.scrollTo({
 
-         left: position.x,
 
-         top: position.y,
 
-         // $flow-disable-line
 
-         behavior: shouldScroll.behavior
 
-       })
 
-     } else {
 
-       window.scrollTo(position.x, position.y)
 
-     }
 
-   }
 
- }
 
 
  |