diff --git a/navigation/navigation-tests.ts b/navigation/navigation-tests.ts
index e0871a2672..758e0e53f5 100644
--- a/navigation/navigation-tests.ts
+++ b/navigation/navigation-tests.ts
@@ -1,117 +1,138 @@
///
-// History Manager
-class LogHistoryManager extends Navigation.HashHistoryManager {
- addHistory(state: Navigation.State, url: string) {
- console.log('add history');
- super.addHistory(state, url);
- }
-}
-
-// State Router
-class LogStateRouter extends Navigation.StateRouter {
- getData(route: string): { state: Navigation.State; data: any } {
- console.log('get data');
- return super.getData(route);
- }
-}
-
-// Settings
-Navigation.settings.router = new LogStateRouter();
-Navigation.settings.historyManager = new LogHistoryManager();
-Navigation.settings.stateIdKey = 'state';
-
-// Configuration
-Navigation.StateInfoConfig.build([
- { key: 'home', initial: 'page', states: [
- { key: 'page', route: '' }
- ]},
- { key: 'person', initial: 'list', states: [
- { key: 'list', route: 'people/{page}', transitions: [
- { key: 'select', to: 'details' }
- ], defaults: { page: 1 }, trackCrumbTrail: false },
- { key: 'details', route: 'person/{id}', defaultTypes: { id: 'number' } }
- ]}
-]);
-
-// StateInfo
-var dialogs = Navigation.StateInfoConfig.dialogs;
-var home = dialogs['home'];
-var homePage = home.states['page'];
-var homeKey = home.key;
-var homePageKey = homePage.key;
-homePage = home.initial;
-var person = dialogs['person'];
-var personList = person.states['list'];
-var personDetails = person.states['details'];
-var personListSelect = personList.transitions['select'];
-personList = personListSelect.parent;
-personDetails = personListSelect.to;
-var pageDefault = personList.defaults.page;
-var idDefaultType = personDetails.defaultTypes.id;
-
-// StateNavigator
-personList.dispose = () => {};
-personList.navigating = (data, url, navigate) => {
- navigate();
-};
-personList.navigated = (data) => {};
-
-// State Handler
-class LogStateHandler extends Navigation.StateHandler {
- getNavigationData(state: Navigation.State, url: string): any {
- console.log('get navigation data');
- super.getNavigationData(state, url);
- }
-}
-homePage.stateHandler = new LogStateHandler();
-personList.stateHandler = new LogStateHandler();
-personDetails.stateHandler = new LogStateHandler();
-
-// Navigation Event
-var navigationListener =
-(oldState: Navigation.State, state: Navigation.State, data: any) => {
- Navigation.StateController.offNavigate(navigationListener);
-};
-Navigation.StateController.onNavigate(navigationListener);
-
-// Navigation
-Navigation.start('home');
-Navigation.StateController.navigate('person');
-Navigation.StateController.refresh();
-Navigation.StateController.refresh({ page: 2 });
-Navigation.StateController.navigate('select', { id: 10 });
-var canGoBack: boolean = Navigation.StateController.canNavigateBack(1);
-Navigation.StateController.navigateBack(1);
-
-// Navigation Link
-var link = Navigation.StateController.getNavigationLink('person');
-link = Navigation.StateController.getRefreshLink();
-link = Navigation.StateController.getRefreshLink({ page: 2 });
-link = Navigation.StateController.getNavigationLink('select', { id: 10 });
-var nextDialog = Navigation.StateController.getNextState('select').parent;
-person = nextDialog;
-Navigation.StateController.navigateLink(link);
-link = Navigation.StateController.getNavigationBackLink(1);
-var crumb = Navigation.StateController.crumbs[0];
-link = crumb.navigationLink;
-
-// StateContext
-Navigation.StateController.navigate('home');
-Navigation.StateController.navigate('person');
-home = Navigation.StateContext.previousDialog;
-homePage = Navigation.StateContext.previousState;
-person === Navigation.StateContext.dialog;
-personList === Navigation.StateContext.state;
-var url: string = Navigation.StateContext.url;
-var page: number = Navigation.StateContext.data.page;
-
-// Navigation Data
-Navigation.StateController.refresh({ page: 2 });
-var data = Navigation.StateContext.includeCurrentData({ sort: 'name' }, ['page']);
-Navigation.StateController.refresh(data);
-Navigation.StateContext.clear('sort');
-var data = Navigation.StateContext.includeCurrentData({ pageSize: 10 });
-Navigation.StateController.refresh(data);
-Navigation.StateContext.clear();
-Navigation.StateController.refresh();
+module NavigationTests {
+ // History Manager
+ class LogHistoryManager extends Navigation.HashHistoryManager {
+ addHistory(state: Navigation.State, url: string) {
+ console.log('add history');
+ super.addHistory(state, url);
+ }
+ }
+
+ // Crumb Trail Persister
+ class LogCrumbTrailPersister extends Navigation.CrumbTrailPersister {
+ load(crumbTrail: string): string {
+ console.log('load');
+ return crumbTrail;
+ }
+
+ save(crumbTrail: string): string {
+ console.log('save');
+ return crumbTrail;
+ }
+ }
+
+ // State Router
+ class LogStateRouter extends Navigation.StateRouter {
+ getData(route: string): { state: Navigation.State; data: any } {
+ console.log('get data');
+ return super.getData(route);
+ }
+ }
+
+ // Settings
+ Navigation.settings.router = new LogStateRouter();
+ Navigation.settings.historyManager = new LogHistoryManager();
+ Navigation.settings.crumbTrailPersister = new LogCrumbTrailPersister();
+ Navigation.settings.stateIdKey = 'state';
+
+ // Configuration
+ Navigation.StateInfoConfig.build([
+ { key: 'home', initial: 'page', states: [
+ { key: 'page', route: '' }
+ ]},
+ { key: 'person', initial: 'list', states: [
+ { key: 'list', route: ['people/{page}', 'people/{page}/sort/{sort}'], transitions: [
+ { key: 'select', to: 'details' }
+ ], defaults: { page: 1 }, trackCrumbTrail: false },
+ { key: 'details', route: 'person/{id}', trackTypes: false, defaultTypes: { id: 'number' } }
+ ]}
+ ]);
+
+ // StateInfo
+ var dialogs = Navigation.StateInfoConfig.dialogs;
+ var home = dialogs['home'];
+ var homePage = home.states['page'];
+ var homeKey = home.key;
+ var homePageKey = homePage.key;
+ homePage = home.initial;
+ var person = dialogs['person'];
+ var personList = person.states['list'];
+ var personDetails = person.states['details'];
+ var personListSelect = personList.transitions['select'];
+ personList = personListSelect.parent;
+ personDetails = personListSelect.to;
+ var pageDefault = personList.defaults.page;
+ var idDefaultType = personDetails.defaultTypes.id;
+
+ // StateNavigator
+ personList.dispose = () => {};
+ personList.navigating = (data, url, navigate) => {
+ navigate([]);
+ };
+ personList.navigated = (data, asyncData) => {};
+ personDetails.navigating = (data, url, navigate) => {
+ navigate();
+ };
+ personDetails.navigated = (data) => {};
+
+ // State Handler
+ class LogStateHandler extends Navigation.StateHandler {
+ getNavigationData(state: Navigation.State, url: string): any {
+ console.log('get navigation data');
+ super.getNavigationData(state, url);
+ }
+ }
+ homePage.stateHandler = new LogStateHandler();
+ personList.stateHandler = new LogStateHandler();
+ personDetails.stateHandler = new LogStateHandler();
+
+ // Navigation Event
+ var navigationListener =
+ (oldState: Navigation.State, state: Navigation.State, data: any) => {
+ Navigation.StateController.offNavigate(navigationListener);
+ };
+ Navigation.StateController.onNavigate(navigationListener);
+
+ // Navigation
+ Navigation.start('home');
+ Navigation.StateController.navigate('person');
+ Navigation.StateController.refresh();
+ Navigation.StateController.refresh({ page: 2 });
+ Navigation.StateController.navigate('select', { id: 10 });
+ var canGoBack: boolean = Navigation.StateController.canNavigateBack(1);
+ Navigation.StateController.navigateBack(1);
+
+ // Navigation Link
+ var link = Navigation.StateController.getNavigationLink('person');
+ link = Navigation.StateController.getRefreshLink();
+ link = Navigation.StateController.getRefreshLink({ page: 2 });
+ link = Navigation.StateController.getNavigationLink('select', { id: 10 });
+ var nextDialog = Navigation.StateController.getNextState('select').parent;
+ person = nextDialog;
+ Navigation.StateController.navigateLink(link);
+ link = Navigation.StateController.getNavigationBackLink(1);
+ var crumb = Navigation.StateController.crumbs[0];
+ link = crumb.navigationLink;
+ Navigation.StateController.navigateLink(link, true);
+
+ // StateContext
+ Navigation.StateController.navigate('home');
+ Navigation.StateController.navigate('person');
+ home = Navigation.StateContext.previousDialog;
+ homePage = Navigation.StateContext.previousState;
+ person === Navigation.StateContext.dialog;
+ personList === Navigation.StateContext.state;
+ var url: string = Navigation.StateContext.url;
+ var page: number = Navigation.StateContext.data.page;
+
+ // Navigation Data
+ Navigation.StateController.refresh({ page: 2 });
+ var data = Navigation.StateContext.includeCurrentData({ sort: 'name' }, ['page']);
+ Navigation.StateController.refresh(data);
+ Navigation.StateContext.clear('sort');
+ var data = Navigation.StateContext.includeCurrentData({ pageSize: 10 });
+ Navigation.StateController.refresh(data);
+ Navigation.StateContext.clear();
+ Navigation.StateController.refresh();
+}
\ No newline at end of file
diff --git a/navigation/navigation.d.ts b/navigation/navigation.d.ts
index 7cb8308971..59af79ca29 100644
--- a/navigation/navigation.d.ts
+++ b/navigation/navigation.d.ts
@@ -1,4 +1,4 @@
-// Type definitions for Navigation 1.0
+// Type definitions for Navigation 1.1.0
// Project: http://grahammendick.github.io/navigation/
// Definitions by: Graham Mendick
// Definitions: https://github.com/borisyankov/DefinitelyTyped
@@ -61,15 +61,20 @@ declare module Navigation {
*/
title?: string;
/**
- * Gets the route Url pattern
+ * Gets the route Url patterns
*/
- route: string;
+ route: string | string[];
/**
* Gets a value that indicates whether to maintain crumb trail
* information e.g PreviousState. This can be used together with Route
* to produce user friendly Urls
*/
trackCrumbTrail?: boolean;
+ /**
+ * Gets a value that indicates whether NavigationData Types are
+ * preserved when navigating
+ */
+ trackTypes?: boolean;
}
/**
@@ -175,20 +180,35 @@ declare module Navigation {
*/
title: string;
/**
- * Gets the route Url pattern
+ * Gets the route Url patterns
*/
- route: string;
+ route: string | string[];
/**
* Gets a value that indicates whether to maintain crumb trail
* information e.g PreviousState. This can be used together with Route
* to produce user friendly Urls
*/
trackCrumbTrail: boolean;
+ /**
+ * Gets a value that indicates whether NavigationData Types are
+ * preserved when navigating
+ */
+ trackTypes: boolean;
/**
* Gets or sets the IStateHandler responsible for building and parsing
- * avigation links to this State
+ * navigation links to this State
*/
stateHandler: IStateHandler;
+ /**
+ * Called on the old State (this is not the same as the previous
+ * State) before navigating to a different State
+ * @param state The new State
+ * @param data The new NavigationData
+ * @param url The new target location
+ * @param unload The function to call to continue to navigate
+ * @param history A value indicating whether browser history was used
+ */
+ unloading: (state: State, data: any, url: string, unload: () => void, history?: boolean) => void;
/**
* Called on the old State (this is not the same as the previous
* State) after navigating to a different State
@@ -197,15 +217,17 @@ declare module Navigation {
/**
* Called on the current State after navigating to it
* @param data The current NavigationData
+ * @param asyncData The data passed asynchronously while navigating
*/
- navigated: (data: any) => void;
+ navigated: (data: any, asyncData?: any) => void;
/**
* Called on the new State before navigating to it
* @param data The new NavigationData
* @param url The new target location
- * @param navigate The function to call to continue to navigate
+ * @param navigate The function to call to continue to navigate
+ * @param history A value indicating whether browser history was used
*/
- navigating: (data: any, url: string, navigate: () => void) => void;
+ navigating: (data: any, url: string, navigate: (asyncData?: any) => void, history?: boolean) => void;
}
/**
@@ -366,6 +388,84 @@ declare module Navigation {
*/
getUrl(anchor: HTMLAnchorElement): string;
}
+
+ /**
+ * Provides the base functionality for crumb trail persistence mechanisms
+ */
+ class CrumbTrailPersister {
+ /**
+ * Overridden by derived classes to return the persisted crumb trail
+ * @param crumbTrail The key, returned from the save function, to
+ * identify the persisted crumb trail
+ * @returns The crumb trail holding navigation and data information
+ */
+ load(crumbTrail: string): string;
+ /**
+ * Overridden by derived classes to persist the crumb trail
+ * @param crumbTrail The crumb trail holding navigation and data
+ * information
+ * @returns The key to be passed to load function for crumb trail
+ * retrieval
+ */
+ save(crumbTrail: string): string;
+ }
+
+ /**
+ * Persists crumb trails, over a specified length, in localStorage.
+ * Prevents the creation of unmanageably long Urls. If used in a browser
+ * without localStorage or outside of a browser environment, then in memory
+ * storage is used
+ */
+ class StorageCrumbTrailPersister extends CrumbTrailPersister {
+ /**
+ * Initializes a new instance of the StorageCrumbTrailPersister class
+ * with a maxLength of 500, historySize of 100 and localStorage as the
+ * storage mechanism
+ */
+ constructor();
+ /**
+ * Initializes a new instance of the StorageCrumbTrailPersister class
+ * with a historySize of 100 and localStorage as the storage mechanism
+ * @param maxLength The length above which any crumb trail will be
+ * stored in localStorage
+ */
+ constructor(maxLength: number);
+ /**
+ * Initializes a new instance of the StorageCrumbTrailPersister class
+ * with localStorage as the storage mechanism
+ * @param maxLength The length above which any crumb trail will be
+ * stored in localStorage
+ * @param historySize The maximum number of crumb trails that will be
+ * held at any one time in localStorage
+ */
+ constructor(maxLength: number, historySize: number);
+ /**
+ * Initializes a new instance of the StorageCrumbTrailPersister class
+ * @param maxLength The length above which any crumb trail will be
+ * stored in the storage
+ * @param historySize The maximum number of crumb trails that will be
+ * held at any one time in the storage
+ * @param storage The storage mechanism
+ */
+ constructor(maxLength: number, historySize: number, storage: Storage);
+ /**
+ * Uses the crumbTrail parameter to determine whether to retrieve the
+ * crumb trail from storage. If retrieved from storage it may be null
+ * @param Key generated by the save function
+ * @returns Either the crumbTrail or the one retrieved value from
+ * storage; can be null if retrieved from storage
+ */
+ load(crumbTrail: string): string;
+ /**
+ * If the crumbTrail is not over the maxLength it is returned.
+ * Otherwise the crumbTrail is stored in storage using a short key,
+ * unique within a given storage session. Also expunges old items from
+ * storage, if the historySize is breached when a new item is added
+ * @param crumbTrail The crumb trail to persist
+ * @returns crumbTrail or short, generated key pointing at crumbTrail
+ */
+ save(crumbTrail: string): string;
+ }
/**
* Defines a contract a class must implement in order to build and parse
@@ -434,6 +534,14 @@ declare module Navigation {
navigationLink: string;
/**
* Initializes a new instance of the Crumb class
+ * @param data The Context Data held at the time of navigating away
+ * from this State
+ * @param state The configuration information associated with this
+ * navigation
+ * @param link The hyperlink navigation to return to the State and pass
+ * the associated Data
+ * @param last A value indicating whether the Crumb is the last in the
+ * crumb trail
*/
constructor(data: any, state: State, link: string, last: boolean);
}
@@ -442,8 +550,18 @@ declare module Navigation {
* Provides access to the Navigation Settings configuration
*/
class NavigationSettings {
+ /**
+ * Gets or sets the builder and parser of State routes
+ */
router: IRouter;
+ /**
+ * Gets or sets the manager of the browser Url
+ */
historyManager: IHistoryManager;
+ /**
+ * Gets or sets the crumb trail persistence mechanism
+ */
+ crumbTrailPersister: CrumbTrailPersister;
/**
* Gets or sets the key that identifies the StateId
*/
@@ -464,6 +582,11 @@ declare module Navigation {
* Gets or sets the application path
*/
applicationPath: string;
+ /**
+ * Gets or sets a value indicating whether the PreviousStateId and
+ * ReturnData should be part of the CrumbTrail
+ */
+ combineCrumbTrail: boolean;
}
/**
@@ -650,6 +773,12 @@ declare module Navigation {
* @param url The target location
*/
static navigateLink(url: string): void;
+ /**
+ * Navigates to the url
+ * @param url The target location
+ * @param history A value indicating whether browser history was used
+ */
+ static navigateLink(url: string, history: boolean): void;
/**
* Gets the next State. Depending on the action will either return the
* 'to' State of a Transition or the 'initial' State of a Dialog
@@ -831,6 +960,11 @@ declare module Navigation {
* @returns The matched route and data
*/
match(path: string): { route: Route; data: any; };
+ /**
+ * Sorts the routes by the comparer
+ * @param compare The route comparer function
+ */
+ sort(compare: (routeA: Route, routeB: Route) => number): void;
}
/**