mirror of https://github.com/abpframework/abp.git
25 changed files with 269 additions and 51 deletions
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../../dist/components/page", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
import { |
|||
Directive, |
|||
TemplateRef, |
|||
ViewContainerRef, |
|||
Input, |
|||
InjectionToken, |
|||
Optional, |
|||
Inject, |
|||
OnInit, |
|||
OnDestroy, |
|||
Injector, |
|||
OnChanges, |
|||
SimpleChanges, |
|||
SimpleChange, |
|||
} from '@angular/core'; |
|||
|
|||
export interface PageRenderStrategy { |
|||
shouldRender(type: string); |
|||
onInit?(type: string, injector: Injector, context?: any); |
|||
onDestroy?(type: string, injector?: Injector, context?: any); |
|||
onContextUpdate?(change: SimpleChange); |
|||
} |
|||
|
|||
export const PAGE_RENDER_STRATEGY = new InjectionToken<PageRenderStrategy>('PAGE_RENDER_STRATEGY'); |
|||
|
|||
@Directive({ selector: '[abpPagePart]' }) |
|||
export class PagePartDirective implements OnInit, OnDestroy, OnChanges { |
|||
hasRendered = false; |
|||
type: string; |
|||
|
|||
@Input() set abpPagePart(type: string) { |
|||
this.type = type; |
|||
const shouldRender = this.shouldRender(type); |
|||
|
|||
if (shouldRender && !this.hasRendered) { |
|||
this.viewContainer.createEmbeddedView(this.templateRef); |
|||
this.hasRendered = true; |
|||
} else if (!shouldRender && this.hasRendered) { |
|||
this.viewContainer.clear(); |
|||
this.hasRendered = false; |
|||
} |
|||
} |
|||
|
|||
@Input('abpPagePartContext') context: any; |
|||
|
|||
constructor( |
|||
private templateRef: TemplateRef<any>, |
|||
private viewContainer: ViewContainerRef, |
|||
@Optional() @Inject(PAGE_RENDER_STRATEGY) private renderLogic: PageRenderStrategy, |
|||
private injector: Injector, |
|||
) {} |
|||
|
|||
ngOnChanges({ context }: SimpleChanges): void { |
|||
if (this.renderLogic?.onContextUpdate) { |
|||
this.renderLogic.onContextUpdate(context); |
|||
} |
|||
} |
|||
|
|||
ngOnInit() { |
|||
if (this.renderLogic?.onInit) { |
|||
this.renderLogic.onInit(this.type, this.injector, this.context); |
|||
} |
|||
} |
|||
|
|||
ngOnDestroy() { |
|||
if (this.renderLogic?.onDestroy) { |
|||
this.renderLogic.onDestroy(this.type, this.injector, this.context); |
|||
} |
|||
} |
|||
|
|||
shouldRender(type: string) { |
|||
if (this.renderLogic) { |
|||
return this.renderLogic.shouldRender(type); |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
import { Component, ViewEncapsulation } from '@angular/core'; |
|||
|
|||
export enum PageParts { |
|||
title = 'PageTitleContainerComponent', |
|||
breadcrumb = 'PageBreadcrumbContainerComponent', |
|||
toolbar = 'PageToolbarContainerComponent', |
|||
} |
|||
|
|||
@Component({ |
|||
selector: 'abp-page-title-container', |
|||
template: ` |
|||
<ng-content></ng-content> |
|||
`,
|
|||
encapsulation: ViewEncapsulation.None, |
|||
}) |
|||
export class PageTitleContainerComponent {} |
|||
|
|||
@Component({ |
|||
selector: 'abp-page-breadcrumb-container', |
|||
template: ` |
|||
<ng-content></ng-content> |
|||
`,
|
|||
encapsulation: ViewEncapsulation.None, |
|||
}) |
|||
export class PageBreadcrumbContainerComponent {} |
|||
|
|||
@Component({ |
|||
selector: 'abp-page-toolbar-container', |
|||
template: ` |
|||
<ng-content></ng-content> |
|||
`,
|
|||
encapsulation: ViewEncapsulation.None, |
|||
}) |
|||
export class PageToolbarContainerComponent {} |
|||
@ -0,0 +1,41 @@ |
|||
<div class="row entry-row"> |
|||
<ng-container *ngIf="titleVisible"> |
|||
<ng-container *ngIf="customTitle; else defaultTitleTemplate"> |
|||
<ng-content select="abp-page-title-container"></ng-content> |
|||
</ng-container> |
|||
</ng-container> |
|||
|
|||
<ng-container *ngIf="breadcrumbVisible"> |
|||
<ng-container *ngIf="customBreadcrumb; else defaultBreadcrumbTemplate"> |
|||
<ng-content select="abp-page-breadcrumb-container"></ng-content> |
|||
</ng-container> |
|||
</ng-container> |
|||
|
|||
<ng-container *ngIf="toolbarVisible"> |
|||
<ng-container *ngIf="customToolbar; else defaultPageToolbarTemplate"> |
|||
<ng-content select="abp-page-toolbar-container"></ng-content> |
|||
</ng-container> |
|||
</ng-container> |
|||
</div> |
|||
|
|||
<ng-content></ng-content> |
|||
|
|||
<ng-template #defaultTitleTemplate> |
|||
<div class="col-auto" *abpPagePart="pageParts.title"> |
|||
<h1 class="content-header-title"> |
|||
{{ title }} |
|||
</h1> |
|||
</div> |
|||
</ng-template> |
|||
|
|||
<ng-template #defaultBreadcrumbTemplate> |
|||
<div class="col-lg-auto pl-lg-0" *abpPagePart="pageParts.breadcrumb"> |
|||
<abp-breadcrumb></abp-breadcrumb> |
|||
</div> |
|||
</ng-template> |
|||
|
|||
<ng-template #defaultPageToolbarTemplate> |
|||
<div class="col" *abpPagePart="pageParts.toolbar; context: record"> |
|||
<abp-page-toolbar [record]="record"></abp-page-toolbar> |
|||
</div> |
|||
</ng-template> |
|||
@ -0,0 +1,32 @@ |
|||
import { Component, Input, ViewEncapsulation, ContentChild } from '@angular/core'; |
|||
import { |
|||
PageTitleContainerComponent, |
|||
PageBreadcrumbContainerComponent, |
|||
PageToolbarContainerComponent, |
|||
PageParts, |
|||
} from './page-parts.component'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-page', |
|||
templateUrl: './page.component.html', |
|||
encapsulation: ViewEncapsulation.None, |
|||
}) |
|||
export class PageComponent { |
|||
@Input() title: string; |
|||
@Input() record: any; |
|||
|
|||
@Input() titleVisible = true; |
|||
@Input() breadcrumbVisible = true; |
|||
@Input() toolbarVisible = true; |
|||
|
|||
pageParts = { |
|||
title: PageParts.title, |
|||
breadcrumb: PageParts.breadcrumb, |
|||
toolbar: PageParts.toolbar, |
|||
}; |
|||
|
|||
@ContentChild(PageTitleContainerComponent) customTitle: PageTitleContainerComponent; |
|||
@ContentChild(PageBreadcrumbContainerComponent) |
|||
customBreadcrumb: PageBreadcrumbContainerComponent; |
|||
@ContentChild(PageToolbarContainerComponent) customToolbar: PageToolbarContainerComponent; |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { UiExtensionsModule } from '@abp/ng.theme.shared/extensions'; |
|||
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
|||
import { CoreModule } from '@abp/ng.core'; |
|||
import { PageComponent } from './page.component'; |
|||
import { |
|||
PageTitleContainerComponent, |
|||
PageBreadcrumbContainerComponent, |
|||
PageToolbarContainerComponent, |
|||
} from './page-parts.component'; |
|||
import { PagePartDirective } from './page-part.directive'; |
|||
|
|||
const exportedDeclarations = [ |
|||
PageComponent, |
|||
PageTitleContainerComponent, |
|||
PageBreadcrumbContainerComponent, |
|||
PageToolbarContainerComponent, |
|||
PagePartDirective, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
declarations: [...exportedDeclarations], |
|||
imports: [CommonModule, UiExtensionsModule, CoreModule, ThemeSharedModule], |
|||
exports: [...exportedDeclarations], |
|||
}) |
|||
export class PageModule {} |
|||
@ -0,0 +1,4 @@ |
|||
export * from './page.module'; |
|||
export * from './page-part.directive'; |
|||
export * from './page-parts.component'; |
|||
export * from './page.component'; |
|||
@ -1,46 +1,36 @@ |
|||
<div class="row entry-row"> |
|||
<div class="col-auto"> |
|||
<h1 class="content-header-title">{{ 'AbpSettingManagement::Settings' | abpLocalization }}</h1> |
|||
</div> |
|||
<div id="breadcrumb" class="col-lg-auto pl-lg-0"> |
|||
<abp-breadcrumb></abp-breadcrumb> |
|||
</div> |
|||
<div class="col"> |
|||
<div class="text-lg-right pt-2" id="AbpContentToolbar"></div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="SettingManagementWrapper"> |
|||
<div class="card"> |
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-12 col-md-3"> |
|||
<ul class="nav flex-column nav-pills" id="nav-tab" role="tablist"> |
|||
<ng-container *abpFor="let setting of settings; trackBy: trackByFn"> |
|||
<li |
|||
(click)="selected = setting" |
|||
class="nav-item pointer" |
|||
*abpPermission="setting.requiredPolicy" |
|||
> |
|||
<a |
|||
class="nav-link" |
|||
[id]="setting.name + '-tab'" |
|||
role="tab" |
|||
[class.active]="setting.name === selected.name" |
|||
>{{ setting.name | abpLocalization }}</a |
|||
<abp-page [title]="'AbpSettingManagement::Settings' | abpLocalization" [toolbarVisible]="false"> |
|||
<div id="SettingManagementWrapper"> |
|||
<div class="card"> |
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-12 col-md-3"> |
|||
<ul class="nav flex-column nav-pills" id="nav-tab" role="tablist"> |
|||
<ng-container *abpFor="let setting of settings; trackBy: trackByFn"> |
|||
<li |
|||
(click)="selected = setting" |
|||
class="nav-item pointer" |
|||
*abpPermission="setting.requiredPolicy" |
|||
> |
|||
</li> |
|||
</ng-container> |
|||
</ul> |
|||
</div> |
|||
<div class="col-12 col-md-9"> |
|||
<div *ngIf="settings.length" class="tab-content"> |
|||
<div class="tab-pane fade show active" [id]="selected.name + '-tab'" role="tabpanel"> |
|||
<ng-container *ngComponentOutlet="selected.component"></ng-container> |
|||
<a |
|||
class="nav-link" |
|||
[id]="setting.name + '-tab'" |
|||
role="tab" |
|||
[class.active]="setting.name === selected.name" |
|||
>{{ setting.name | abpLocalization }}</a |
|||
> |
|||
</li> |
|||
</ng-container> |
|||
</ul> |
|||
</div> |
|||
<div class="col-12 col-md-9"> |
|||
<div *ngIf="settings.length" class="tab-content"> |
|||
<div class="tab-pane fade show active" [id]="selected.name + '-tab'" role="tabpanel"> |
|||
<ng-container *ngComponentOutlet="selected.component"></ng-container> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</abp-page> |
|||
|
|||
Loading…
Reference in new issue