@exalif/ngx-breadcrumbs
Version:
Angular 4+ breadcrumbs on top of native Angular router
248 lines (239 loc) • 11 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Component, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i1 from '@angular/router';
import { NavigationEnd, RouterModule } from '@angular/router';
import { Observable, from, of, BehaviorSubject, concat } from 'rxjs';
import { filter, flatMap, distinct, tap, toArray, first } from 'rxjs/operators';
class BreadcrumbsConfig {
constructor(options = {
postProcess: null,
applyDistinctOn: 'text',
}) {
this.postProcess = null;
this.applyDistinctOn = 'text';
if (!options) {
return;
}
Object.keys(options).forEach((optionKey) => {
this[optionKey] = options[optionKey];
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsConfig, deps: [{ token: BreadcrumbsConfig }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsConfig }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsConfig, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: BreadcrumbsConfig }]; } });
class BreadcrumbsUtils {
static stringFormat(rawTemplate, data) {
const templateRegex = new RegExp('{{[\\s]*[a-zA-Z._]+?[\\s]*}}', 'g');
return rawTemplate.replace(templateRegex, (match) => {
const keyRegex = new RegExp('([a-zA-Z._]+)', 'g');
const key = match.match(keyRegex);
if (!key || !key.length) {
return match;
}
const value = BreadcrumbsUtils.leaf(data, key[0]);
if (!value) {
return key[0];
}
return value;
});
}
static wrapIntoObservable(value) {
if (value instanceof Observable) {
return value;
}
if (this.isPromise(value)) {
return from(Promise.resolve(value));
}
return of(value);
}
static isPromise(value) {
return value && (typeof value.then === 'function');
}
/**
* Access object nested value by giving a path
*
* @param obj The object you want to access value from
* @param path The value path. e.g: `bar.baz`
* @example
* const obj = { foo: { bar: 'Baz' } };
* const path = 'foo.bar';
* leaf(obj, path) // 'Baz'
*/
static leaf(obj, path) {
const result = path.split('.').reduce((value, el) => value[el] || {}, obj);
return BreadcrumbsUtils.isEmptyObject(result) ? null : result;
}
/**
* checks whether an object is empty or not
*
* @param object object to extract values from
* @returns boolean
*/
static isEmptyObject(obj) {
if (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Object]') {
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return false;
}
}
return true;
}
return false;
}
}
class BreadcrumbsResolver {
resolve(route, state) {
const data = route.routeConfig.data;
const path = this.getFullPath(route);
let text = typeof (data.breadcrumbs) === 'string' ? data.breadcrumbs : data.breadcrumbs.text || data.text || path;
text = BreadcrumbsUtils.stringFormat(text, route.data);
const crumbs = [{
text,
path
}];
return of(crumbs);
}
getFullPath(route) {
return this.fetchFullPath(route.pathFromRoot);
}
fetchFullPath(routes) {
return routes.reduce((path, route) => path += this.fetchRelativePath(route.url), '');
}
fetchRelativePath(urlSegments) {
return urlSegments.reduce((path, urlSegment) => path += '/' + urlSegment.path, '');
}
}
class BreadcrumbsService {
constructor(route, router, config, injector) {
this.route = route;
this.router = router;
this.config = config;
this.injector = injector;
this.breadcrumbs = new BehaviorSubject([]);
this.defaultResolver = new BreadcrumbsResolver();
this.router.events.pipe(filter((x) => x instanceof NavigationEnd))
.subscribe((_) => {
const routeRoot = router.routerState.snapshot.root;
this.resolveCrumbs(routeRoot).pipe(flatMap((crumbs) => crumbs), this.config.applyDistinctOn
? distinct((crumb) => crumb[this.config.applyDistinctOn])
: tap(), toArray(), flatMap((crumbs) => {
if (this.config.postProcess) {
const postProcessedCrumb = this.config.postProcess(crumbs);
return BreadcrumbsUtils.wrapIntoObservable(postProcessedCrumb).pipe(first());
}
else {
return of(crumbs);
}
}))
.subscribe((crumbs) => {
this.breadcrumbs.next(crumbs);
});
});
}
get crumbs$() {
return this.breadcrumbs;
}
getCrumbs() {
return this.crumbs$;
}
resolveCrumbs(route) {
let crumbs$;
const data = route.routeConfig && route.routeConfig.data;
if (data && data.breadcrumbs) {
let resolver;
if (data.breadcrumbs.prototype instanceof BreadcrumbsResolver) {
resolver = this.injector.get(data.breadcrumbs);
}
else {
resolver = this.defaultResolver;
}
const result = resolver.resolve(route, this.router.routerState.snapshot);
crumbs$ = BreadcrumbsUtils.wrapIntoObservable(result).pipe(first());
}
else {
crumbs$ = of([]);
}
if (route.firstChild) {
crumbs$ = concat(crumbs$, this.resolveCrumbs(route.firstChild));
}
return crumbs$;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsService, deps: [{ token: i1.ActivatedRoute }, { token: i1.Router }, { token: BreadcrumbsConfig }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.ActivatedRoute }, { type: i1.Router }, { type: BreadcrumbsConfig }, { type: i0.Injector }]; } });
class BreadcrumbsComponent {
constructor(breadcrumbsService) {
this.breadcrumbsService = breadcrumbsService;
this.crumbs$ = this.breadcrumbsService.getCrumbs();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsComponent, deps: [{ token: BreadcrumbsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.1", type: BreadcrumbsComponent, selector: "lib-breadcrumbs", ngImport: i0, template: `
<ol *ngIf="crumbs$ | async as crumbs" class="breadcrumbs__container">
<li *ngFor="let crumb of crumbs; let last = last"
[ngClass]="{ 'breadcrumbs__item--active': last }"
class="breadcrumbs__item"
>
<a *ngIf="!last" [routerLink]="crumb.path">{{ crumb.text }}</a>
<span *ngIf="last">{{ crumb.text }}</span>
</li>
</ol>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsComponent, decorators: [{
type: Component,
args: [{
selector: 'lib-breadcrumbs',
template: `
<ol *ngIf="crumbs$ | async as crumbs" class="breadcrumbs__container">
<li *ngFor="let crumb of crumbs; let last = last"
[ngClass]="{ 'breadcrumbs__item--active': last }"
class="breadcrumbs__item"
>
<a *ngIf="!last" [routerLink]="crumb.path">{{ crumb.text }}</a>
<span *ngIf="last">{{ crumb.text }}</span>
</li>
</ol>
`
}]
}], ctorParameters: function () { return [{ type: BreadcrumbsService }]; } });
// @dynamic
class BreadcrumbsModule {
static forRoot(config) {
return {
ngModule: BreadcrumbsModule,
providers: [
{ provide: BreadcrumbsConfig, useFactory: () => new BreadcrumbsConfig(config) },
BreadcrumbsService,
],
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsModule, declarations: [BreadcrumbsComponent], imports: [CommonModule,
RouterModule], exports: [BreadcrumbsComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsModule, imports: [CommonModule,
RouterModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: BreadcrumbsModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
RouterModule,
],
declarations: [BreadcrumbsComponent],
exports: [BreadcrumbsComponent],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { BreadcrumbsComponent, BreadcrumbsConfig, BreadcrumbsModule, BreadcrumbsResolver, BreadcrumbsService };
//# sourceMappingURL=exalif-ngx-breadcrumbs.mjs.map