]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
wip: listening to history
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 22 May 2019 06:46:17 +0000 (08:46 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 22 May 2019 06:46:17 +0000 (08:46 +0200)
.gitignore
explorations/html5.html
explorations/html5.ts
src/history/base.ts
src/history/html5.ts
src/history/utils.ts
src/matcher.ts
src/router.ts

index 9ded42c1f648a9c3459b11abd6b316ac18ea8b23..198792ca973886f0b3b4fee22484bb83a4c667e4 100644 (file)
@@ -3,3 +3,4 @@ examples_dist
 node_modules
 coverage
 .nyc_output
+.rpt2_cache
index e3e0b259bb696d1d0d52e1157f7b79917f38944c..bec4eec7db8d4a7effd3174b4ec05b5c1133bf41 100644 (file)
@@ -1,11 +1,17 @@
 <!DOCTYPE html>
 <html lang="en">
-<head>
-  <meta charset="UTF-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <meta http-equiv="X-UA-Compatible" content="ie=edge">
-  <title>Testing History HTML5</title>
-</head>
-<body>
-</body>
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
+    <title>Testing History HTML5</title>
+  </head>
+  <body>
+    <div id="app">
+      <label>
+        <input type="checkbox" onchange="cancel = !cancel" /> Cancel Next
+        Navigation
+      </label>
+    </div>
+  </body>
 </html>
index 34f257592dba4c3e43d32fcc3f42559b8517ec6a..ac52cc593674c507ae499011d7fd3745e71047bb 100644 (file)
@@ -1,6 +1,13 @@
 import { Router, HTML5History } from '../src'
 import { RouteComponent } from '../src/types'
 
+declare global {
+  interface Window {
+    cancel: boolean
+  }
+}
+window.cancel = false
+
 const component: RouteComponent = {
   template: `<div>A component</div>`,
 }
@@ -20,6 +27,7 @@ const r = new Router({
   routes: [
     { path: '/', component },
     { path: '/users/:id', name: 'user', component },
+    { path: '/n/:n', name: 'increment', component },
     { path: '/multiple/:a/:b', name: 'user', component },
     {
       path: '/with-guard/:n',
@@ -50,6 +58,11 @@ r.beforeEach((to, from, next) => {
   next()
 })
 
+r.beforeEach((to, from, next) => {
+  if (window.cancel) return next(false)
+  next()
+})
+
 r.afterEach((to, from) => {
   console.log(
     `After guard: from ${from.fullPath} to ${
@@ -74,6 +87,7 @@ window.r = r
 h.listen((to, from, { type }) => {
   console.log(`popstate(${type})`, { to, from })
 })
+
 async function run() {
   // r.push('/multiple/one/two')
 
index b61cd720a1fe0bc5238aa0676579c6190b6eea5a..1c0580caa8bb66bf5cc5622cd3a3c660fc969872 100644 (file)
@@ -57,6 +57,7 @@ export abstract class BaseHistory {
   // previousState: object
   location: HistoryLocationNormalized = START
   base: string = ''
+  paused: boolean = false
   utils = utils
 
   /**
@@ -73,6 +74,13 @@ export abstract class BaseHistory {
    */
   abstract replace(to: HistoryLocation): void
 
+  /**
+   * Goes back in history log. Should trigger any listener added via
+   * `listen`. If we are on the first entry, behaviour may change depending
+   * on implementation
+   */
+  abstract back(): void
+
   /**
    * Notifies back whenever the location changes due to user interactions
    * outside of the applicaiton. For example, going back/forward on a
index adb3da4cb97cdef0dc1aa375627cbafe15774d28..1a111c4a345e7f88588d017147f1aacb2ca64475 100644 (file)
@@ -67,6 +67,8 @@ export class HTML5History extends BaseHistory {
 
   push(to: HistoryLocation, data?: HistoryState) {
     // replace current entry state to add the forward value
+    // TODO: should be removed and let the user normalize the location?
+    // or make it fast so normalization on a normalized object is fast
     const normalized = this.utils.normalizeLocation(to)
     this.history.replaceState(
       buildState(
@@ -89,6 +91,11 @@ export class HTML5History extends BaseHistory {
     this.location = normalized
   }
 
+  back() {
+    // TODO: do not trigger listen
+    this.history.back()
+  }
+
   listen(callback: NavigationCallback) {
     // settup the listener and prepare teardown callbacks
     this._listeners.push(callback)
@@ -122,6 +129,10 @@ export class HTML5History extends BaseHistory {
         state,
         location: this.location,
       })
+      if (this.paused) {
+        cs.info('Ignored beacuse paused')
+        return
+      }
       const from = this.location
       // we have the state from the old entry, not the current one being removed
       // TODO: correctly parse pathname
index 902ece634e1c1e927b8c84a53122d1e969f58c7e..a0aa5892eceffa8cdd38da084da1297b0ed1672d 100644 (file)
@@ -52,7 +52,6 @@ export function parseURL(location: string): HistoryLocationNormalized {
  * @param search
  */
 export function parseQuery(search: string): HistoryQuery {
-  // TODO: optimize by using a for loop
   const hasLeadingIM = search[0] === '?'
   const query: HistoryQuery = {}
   const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&')
index f5fa85a78634f5b765f560dca7f88c5c982e862f..f5cdf4be678a15d85b006dbcfaa731df99cd20e0 100644 (file)
@@ -13,6 +13,8 @@ interface RouteMatcher {
   resolve: (params?: RouteParams) => string
   record: RouteRecord // TODO: NormalizedRouteRecord?
   parent: RouteMatcher | void
+  // TODO: children so they can be removed
+  // children: RouteMatcher[]
   keys: string[]
 }
 
index 6cb0eee3622a87264c78a60fb45e8b25a4618d9d..b5a99937f5f976842413f8c7982a19a30ec072fc 100644 (file)
@@ -1,4 +1,8 @@
-import { BaseHistory, HistoryLocationNormalized } from './history/base'
+import {
+  BaseHistory,
+  HistoryLocationNormalized,
+  NavigationType,
+} from './history/base'
 import { RouterMatcher } from './matcher'
 import {
   RouteLocation,
@@ -35,14 +39,39 @@ export class Router {
 
     this.matcher = new RouterMatcher(options.routes)
 
-    this.history.listen((to, from, info) => {
+    this.history.listen(async (to, from, info) => {
       const matchedRoute = this.matchLocation(to, this.currentRoute)
       // console.log({ to, matchedRoute })
       // TODO: navigate & guards
+      const toLocation: RouteLocationNormalized = { ...to, ...matchedRoute }
+
+      try {
+        await this.navigate(toLocation, this.currentRoute)
 
-      this.currentRoute = {
-        ...to,
-        ...matchedRoute,
+        // accept current navigation
+        this.currentRoute = {
+          ...to,
+          ...matchedRoute,
+        }
+      } catch (error) {
+        // TODO: use the push/replace techieque with any navigation to
+        // preserve history when moving forward
+        if (error instanceof NavigationGuardRedirect) {
+          this.push(error.to)
+        } else {
+          // TODO: handle abort and redirect correctly
+          // if we were going back, we push and discard the rest of the history
+          if (info.type === NavigationType.back) {
+            this.history.push(from)
+          } else {
+            // TODO: go back because we cancelled, then
+            // or replace and not discard the rest of history. Check issues, there was one talking about this
+            // behaviour, maybe we can do better
+            this.history.paused = true
+            this.history.back()
+            this.history.paused = false
+          }
+        }
       }
     })
   }
@@ -84,6 +113,13 @@ export class Router {
     }
   }
 
+  async push(to: RouteLocation): Promise<RouteLocationNormalized> {
+    // match the location
+    const { url, location } =
+    let url: HistoryLocationNormalized
+      let location: MatcherLocationNormalized
+  }
+
   /**
    * Trigger a navigation, adding an entry to the history stack. Also apply all navigation
    * guards first
@@ -92,6 +128,7 @@ export class Router {
   async push(to: RouteLocation): Promise<RouteLocationNormalized> {
     let url: HistoryLocationNormalized
     let location: MatcherLocationNormalized
+    // TODO: refactor into matchLocation to return location and url
     if (typeof to === 'string' || 'path' in to) {
       url = this.history.utils.normalizeLocation(to)
       // TODO: should allow a non matching url to allow dynamic routing to work
@@ -232,7 +269,8 @@ export class Router {
   beforeEach(guard: NavigationGuard): ListenerRemover {
     this.beforeGuards.push(guard)
     return () => {
-      this.beforeGuards.splice(this.beforeGuards.indexOf(guard), 1)
+      const i = this.beforeGuards.indexOf(guard)
+      if (i > -1) this.beforeGuards.splice(i, 1)
     }
   }
 
@@ -243,7 +281,8 @@ export class Router {
   afterEach(guard: PostNavigationGuard): ListenerRemover {
     this.afterGuards.push(guard)
     return () => {
-      this.afterGuards.splice(this.afterGuards.indexOf(guard), 1)
+      const i = this.afterGuards.indexOf(guard)
+      if (i > -1) this.afterGuards.splice(i, 1)
     }
   }
 }