Skip to content

Commit

Permalink
support replace for the router and history managers
Browse files Browse the repository at this point in the history
  • Loading branch information
agubler committed Dec 3, 2020
1 parent 5913b7b commit 18929b5
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/routing/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ export class Router extends Evented<{ nav: NavEvent; route: RouteEvent; outlet:
this._history.set(path);
}

/**
* Replaces the path against the registered history manager
*
* @param path The path to set on the history manager
*/
public replacePath(path: string): void {
this._history.replace(path);
}

public start() {
const { HistoryManager = HashHistory, base, window } = this._options;
this._history = new HistoryManager({ onChange: this._onChange, base, window });
Expand Down
8 changes: 7 additions & 1 deletion src/routing/history/HashHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class HashHistory implements History {
this._window = window;
}

start() {
public start() {
this._window.addEventListener('hashchange', this._onChange, false);
this._current = this.normalizePath(this._window.location.hash);
this._onChangeFunction(this._current);
Expand All @@ -33,6 +33,12 @@ export class HashHistory implements History {
this._onChange();
}

public replace(path: string) {
const { pathname, search } = this._window.location;
this._window.location.replace(pathname + search + this.prefix(path));
this._onChange();
}

public get current(): string {
return this._current;
}
Expand Down
6 changes: 5 additions & 1 deletion src/routing/history/MemoryHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class MemoryHistory implements History {
this._onChangeFunction = onChange;
}

start() {
public start() {
this._onChange();
}

Expand All @@ -24,6 +24,10 @@ export class MemoryHistory implements History {
this._onChange();
}

public replace(path: string) {
this.set(path);
}

public get current(): string {
return this._current;
}
Expand Down
12 changes: 11 additions & 1 deletion src/routing/history/StateHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class StateHistory implements HistoryInterface {
}
}

start() {
public start() {
this._window.addEventListener('popstate', this._onChange, false);
this._onChange();
}
Expand All @@ -72,6 +72,16 @@ export class StateHistory implements HistoryInterface {
this._onChange();
}

public replace(path: string) {
const value = stripBase(this._base, path);
if (this._current === value) {
return;
}

this._window.history.replaceState({}, '', this._setBasePath(value));
this._onChange();
}

public get current(): string {
return this._current;
}
Expand Down
10 changes: 10 additions & 0 deletions src/routing/interfaces.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ export interface RouterInterface {
*/
setPath(path: string): void;

/**
* Replaces the path on the underlying history manager
*/
replacePath(path: string): void;

/**
* Returns the outlet context if matched
*/
Expand Down Expand Up @@ -217,6 +222,11 @@ export interface History {
*/
set(path: string): void;

/**
* Replaces the path on the history manager
*/
replace(path: string): void;

/**
* Adds a prefix to the path if the history manager requires
*/
Expand Down
1 change: 0 additions & 1 deletion tests/routing/unit/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,6 @@ describe('Router', () => {

describe('redirect', () => {
it('should redirect from a default route', () => {
debugger;
const router = new Router(
[
{
Expand Down
30 changes: 30 additions & 0 deletions tests/routing/unit/history/HashHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ class MockLocation {
get hash() {
return this._hash;
}

get pathname() {
return 'pathname';
}

get search() {
return '';
}

replace(value: string) {
const [, hash] = value.split('#');
const newHash = hash[0] !== '#' ? `#${hash}` : hash;
if (newHash !== this._hash) {
this._hash = newHash;
this._change();
}
}
}

class MockWindow {
Expand Down Expand Up @@ -80,6 +97,19 @@ describe('HashHistory', () => {
assert.strictEqual(history.current, 'new');
});

it('Calls onChange on replace', () => {
const onChange = stub();
const history = new HashHistory({ onChange, window: mockWindow });
history.start();
assert.isTrue(onChange.calledWith('current'));
assert.isTrue(onChange.calledOnce);
assert.strictEqual(history.current, 'current');
history.replace('new');
assert.isTrue(onChange.calledTwice);
assert.isTrue(onChange.secondCall.calledWith('new'));
assert.strictEqual(history.current, 'new');
});

it('should add hash prefix', () => {
const onChange = stub();
const history = new HashHistory({ onChange, window: mockWindow });
Expand Down
13 changes: 13 additions & 0 deletions tests/routing/unit/history/MemoryHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ describe('MemoryHistory', () => {
assert.strictEqual(history.current, 'new');
});

it('Calls onChange on replace', () => {
const onChange = stub();
const history = new MemoryHistory({ onChange });
history.start();
assert.isTrue(onChange.calledWith('/'));
assert.isTrue(onChange.calledOnce);
assert.strictEqual(history.current, '/');
history.replace('new');
assert.isTrue(onChange.calledTwice);
assert.isTrue(onChange.secondCall.calledWith('new'));
assert.strictEqual(history.current, 'new');
});

it('Does not call onChange on set if paths match', () => {
const onChange = stub();
const history = new MemoryHistory({ onChange });
Expand Down
8 changes: 8 additions & 0 deletions tests/routing/unit/history/StateHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ describe('StateHistory', () => {
assert.equal(sandbox.contentWindow!.location.pathname, '/foo');
});

it('replace path', () => {
const history = new StateHistory({ onChange, window: sandbox.contentWindow! });
history.start();
history.replace('/foo');
assert.equal(history.current, 'foo');
assert.equal(sandbox.contentWindow!.location.pathname, '/foo');
});

it('update path, does not update path if path is set to the current value', () => {
const history = new StateHistory({ onChange, window: sandbox.contentWindow! });
history.start();
Expand Down

0 comments on commit 18929b5

Please sign in to comment.