-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e4b6703
commit 5068b0f
Showing
22 changed files
with
1,362 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Router | ||
|
||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.4. | ||
|
||
## Code scaffolding | ||
|
||
Run `ng generate component component-name --project router` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project router`. | ||
> Note: Don't forget to add `--project router` or else it will be added to the default project in your `angular.json` file. | ||
## Build | ||
|
||
Run `ng build router` to build the project. The build artifacts will be stored in the `dist/` directory. | ||
|
||
## Publishing | ||
|
||
After building your library with `ng build router`, go to the dist folder `cd dist/router` and run `npm publish`. | ||
|
||
## Running unit tests | ||
|
||
Run `ng test router` to execute the unit tests via [Karma](https://karma-runner.github.io). | ||
|
||
## Further help | ||
|
||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Karma configuration file, see link for more information | ||
// https://karma-runner.github.io/1.0/config/configuration-file.html | ||
|
||
module.exports = function (config) { | ||
config.set({ | ||
basePath: '', | ||
frameworks: ['jasmine', '@angular-devkit/build-angular'], | ||
plugins: [ | ||
require('karma-jasmine'), | ||
require('karma-chrome-launcher'), | ||
require('karma-jasmine-html-reporter'), | ||
require('karma-coverage-istanbul-reporter'), | ||
require('@angular-devkit/build-angular/plugins/karma') | ||
], | ||
client: { | ||
clearContext: false // leave Jasmine Spec Runner output visible in browser | ||
}, | ||
coverageIstanbulReporter: { | ||
dir: require('path').join(__dirname, '../../coverage/router'), | ||
reports: ['html', 'lcovonly', 'text-summary'], | ||
fixWebpackSourcePaths: true | ||
}, | ||
reporters: ['progress', 'kjhtml'], | ||
port: 9876, | ||
colors: true, | ||
logLevel: config.LOG_INFO, | ||
autoWatch: true, | ||
browsers: ['Chrome'], | ||
singleRun: false, | ||
restartOnFileChange: true | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", | ||
"dest": "../../dist/router", | ||
"lib": { | ||
"entryFile": "src/public-api.ts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "router", | ||
"version": "0.0.1", | ||
"peerDependencies": { | ||
"@angular/common": "^9.1.4", | ||
"@angular/core": "^9.1.4", | ||
"tslib": "^1.10.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { Directive, HostBinding, HostListener, Input, Output, EventEmitter, Optional } from '@angular/core'; | ||
import { Router } from './router.service'; | ||
import { RouterComponent } from './router.component'; | ||
|
||
/** | ||
* The LinkTo directive links to routes in your app | ||
* | ||
* Links are pushed to the `Router` service to trigger a route change. | ||
* Query params can be represented as an object or a string of names/values | ||
* | ||
* <a linkTo="/home/page" [queryParams]="{ id: 123 }">Home Page</a> | ||
* <a [linkTo]="'/pages' + page.id">Page 1</a> | ||
*/ | ||
@Directive({ selector: '[linkTo]' }) | ||
export class LinkTo { | ||
@Input() target: string; | ||
@HostBinding('href') linkHref; | ||
|
||
@Input() set linkTo(href: string){ | ||
this._href = href; | ||
this._updateHref(); | ||
} | ||
|
||
@Input() set queryParams(params: string) { | ||
this._query = params; | ||
this._updateHref(); | ||
} | ||
|
||
@Output() hrefUpdated: EventEmitter<string> = new EventEmitter<string>(); | ||
|
||
private _href: string; | ||
private _query: string; | ||
|
||
constructor(private router: Router, @Optional() private routerComp: RouterComponent) {} | ||
|
||
/** | ||
* Handles click events on the associated link | ||
* Prevents default action for non-combination click events without a target | ||
*/ | ||
@HostListener('click', ['$event']) | ||
onClick(event) { | ||
if (!this._comboClick(event) && !this.target) { | ||
this.router.go(this._href, this._query); | ||
|
||
event.preventDefault(); | ||
} | ||
} | ||
|
||
private _updateHref() { | ||
let path = this._cleanUpHref(this._href); | ||
|
||
this.linkHref = this.router.getExternalUrl(path); | ||
this.hrefUpdated.emit(this.linkHref); | ||
} | ||
|
||
/** | ||
* Determines whether the click event happened with a combination of other keys | ||
*/ | ||
private _comboClick(event) { | ||
let buttonEvent = event.which || event.button; | ||
|
||
return (buttonEvent > 1 || event.ctrlKey || event.metaKey || event.shiftKey); | ||
} | ||
|
||
private _cleanUpHref(href: string = ''): string { | ||
// Check for trailing slashes in the path | ||
while (href.length > 1 && href.substr(-1) === '/') { | ||
// Remove trailing slashes | ||
href = href.substring(0, href.length - 1); | ||
} | ||
|
||
return href; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Observable } from 'rxjs'; | ||
|
||
export interface Params { | ||
[param: string]: any; | ||
} | ||
|
||
export class RouteParams extends Observable<Params> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { | ||
Component, | ||
OnInit, | ||
Input, | ||
Type, | ||
ViewChild, | ||
ElementRef, | ||
Injector, | ||
ɵrenderComponent as renderComponent, | ||
ɵmarkDirty as markDirty, | ||
ɵcreateInjector as createInjector | ||
} from "@angular/core"; | ||
|
||
import { Subject, BehaviorSubject, merge, of } from "rxjs"; | ||
import { tap, distinctUntilChanged, filter, takeUntil, mergeMap } from "rxjs/operators"; | ||
|
||
import { LoadComponent, Route } from "./route"; | ||
import { RouteParams, Params } from "./route-params.service"; | ||
import { RouterComponent } from "./router.component"; | ||
|
||
|
||
@Component({ | ||
selector: "route", | ||
template: ` | ||
<div #outlet></div> | ||
` | ||
}) | ||
export class RouteComponent implements OnInit { | ||
private destroy$ = new Subject(); | ||
@ViewChild("outlet", { read: ElementRef, static: true }) outlet: ElementRef; | ||
@Input() path: string; | ||
@Input() component: Type<any>; | ||
@Input() loadComponent: LoadComponent; | ||
route!: Route; | ||
rendered = null; | ||
private _routeParams$ = new BehaviorSubject<Params>({}); | ||
routeParams$ = this._routeParams$.asObservable(); | ||
|
||
constructor(private injector: Injector, private router: RouterComponent) {} | ||
|
||
ngOnInit(): void { | ||
// account for root level routes, don't add the basePath | ||
const path = this.router.parentRouterComponent | ||
? this.router.basePath + this.path | ||
: this.path; | ||
|
||
this.route = this.router.registerRoute({ | ||
path, | ||
component: this.component, | ||
loadComponent: this.loadComponent | ||
}); | ||
|
||
const activeRoute$ = this.router.activeRoute$ | ||
.pipe( | ||
filter(ar => ar !== null), | ||
distinctUntilChanged(), | ||
mergeMap(current => { | ||
if (current.route === this.route) { | ||
this._routeParams$.next(current.params); | ||
|
||
if (!this.rendered) { | ||
return this.loadAndRenderRoute(current.route); | ||
} | ||
} else if (this.rendered) { | ||
return of(this.clearView()); | ||
} | ||
|
||
return of(null); | ||
}) | ||
); | ||
|
||
const routeParams$ = this._routeParams$ | ||
.pipe( | ||
distinctUntilChanged(), | ||
filter(() => !!this.rendered), | ||
tap(() => markDirty(this.rendered)) | ||
); | ||
|
||
merge(activeRoute$, routeParams$).pipe( | ||
takeUntil(this.destroy$), | ||
).subscribe(); | ||
} | ||
|
||
ngOnDestroy() { | ||
this.destroy$.next(); | ||
} | ||
|
||
loadAndRenderRoute(route: Route) { | ||
if (route.loadComponent) { | ||
return route.loadComponent().then(component => { | ||
return this.renderView(component, this.outlet.nativeElement); | ||
}); | ||
} else { | ||
return of(this.renderView(route.component, this.outlet.nativeElement)); | ||
} | ||
} | ||
|
||
renderView(component: Type<any>, host: any) { | ||
const cmpInjector = createInjector({}, this.injector, [ | ||
{ provide: RouteParams, useValue: this.routeParams$ } | ||
]); | ||
|
||
this.rendered = renderComponent(component, { | ||
host, | ||
injector: cmpInjector | ||
}); | ||
|
||
return this.rendered; | ||
} | ||
|
||
clearView() { | ||
this.outlet.nativeElement.innerHTML = ""; | ||
this.rendered = null; | ||
|
||
return this.rendered; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Type } from '@angular/core'; | ||
|
||
import { Params } from './route-params.service'; | ||
|
||
export type LoadComponent = () => Promise<Type<any>>; | ||
|
||
export interface Route { | ||
path: string; | ||
component?: Type<any>; | ||
loadComponent?: LoadComponent; | ||
matcher?: RegExp; | ||
} | ||
|
||
export interface ActiveRoute { | ||
route: Route; | ||
params: Params; | ||
} |
Oops, something went wrong.