From f477aa2391922a399acde23bf50ff095b12a287d Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Tue, 13 Sep 2016 17:16:14 -0500 Subject: [PATCH] feat(nav): component url navigation --- src/navigation/deep-linker.ts | 451 +++++++++++++++ src/navigation/test/deep-linker.spec.ts | 517 +++++++++++++++++ src/navigation/test/url-serializer.spec.ts | 628 +++++++++++++++++++++ src/navigation/url-serializer.ts | 267 +++++++++ 4 files changed, 1863 insertions(+) create mode 100644 src/navigation/deep-linker.ts create mode 100644 src/navigation/test/deep-linker.spec.ts create mode 100644 src/navigation/test/url-serializer.spec.ts create mode 100644 src/navigation/url-serializer.ts diff --git a/src/navigation/deep-linker.ts b/src/navigation/deep-linker.ts new file mode 100644 index 00000000000..a851e1eff24 --- /dev/null +++ b/src/navigation/deep-linker.ts @@ -0,0 +1,451 @@ +import { Injectable, OpaqueToken } from '@angular/core'; +import { Location, LocationStrategy, HashLocationStrategy } from '@angular/common'; + +import { App } from '../components/app/app'; +import { convertToViews, isNav, isTab, isTabs, NavSegment, DIRECTION_BACK } from './nav-util'; +import { isArray, isPresent } from '../util/util'; +import { Nav } from '../components/nav/nav'; +import { NavController } from './nav-controller'; +import { Tab } from '../components/tabs/tab'; +import { Tabs } from '../components/tabs/tabs'; +import { UrlSerializer } from './url-serializer'; +import { ViewController } from './view-controller'; + + +/** + * Deep Linking Scenarios: + * 1) Initialize all NavControllers using the initial browser URL + * 2) User clicks browser back button + * 3) User clicks browser forward button + * 4) User changes browser URL + * 5) User clicks link href + * 6) App uses NavController push/pop/setRoot/insert/remove + * + * Terms: + * - URL: The string value found in the browser's URL bar + * - Segment: Deep linker's data about each section between / in the URL + * - Path: Deep linker's array of segments + * - History: Deep linker's string array of internal URL history + * - Location: Angular's Location provider, which abstracts Hash/Path Location Strategies + */ + + +@Injectable() +export class DeepLinker { + segments: NavSegment[] = []; + history: string[] = []; + indexAliasUrl: string; + + constructor(public app: App, public serializer: UrlSerializer, public location: Location) { } + + init() { + // scenario 1: Initial load of all navs from the initial browser URL + const browserUrl = normalizeUrl(this.location.path()); + console.debug(`DeepLinker, init load: ${browserUrl}`); + + // update the Path from the browser URL + this.segments = this.serializer.parse(browserUrl); + + // remember this URL in our internal history stack + this.historyPush(browserUrl); + + // listen for browser URL changes + this.location.subscribe((locationChg: { url: string }) => { + this.urlChange(normalizeUrl(locationChg.url)); + }); + } + + /** + * The browser's location has been updated somehow. + */ + urlChange(browserUrl: string) { + // do nothing if this url is the same as the current one + if (!this.isCurrentUrl(browserUrl)) { + + if (this.isBackUrl(browserUrl)) { + // scenario 2: user clicked the browser back button + // scenario 4: user changed the browser URL to what was the back url was + // scenario 5: user clicked a link href that was the back url + console.debug(`DeepLinker, browser urlChange, back to: ${browserUrl}`); + this.historyPop(); + + } else { + // scenario 3: user click forward button + // scenario 4: user changed browser URL that wasn't the back url + // scenario 5: user clicked a link href that wasn't the back url + console.debug(`DeepLinker, browser urlChange, forward to: ${browserUrl}`); + this.historyPush(browserUrl); + } + + // get the app's root nav + const appRootNav =