mirror of https://github.com/Squidex/squidex.git
32 changed files with 697 additions and 509 deletions
@ -1,44 +1,36 @@ |
|||||
<div class="modal-dialog"> |
<form [formGroup]="editForm" (ngSubmit)="saveSchema()"> |
||||
<div class="modal-content"> |
<sqx-modal-dialog (close)="complete()"> |
||||
<form [formGroup]="editForm" (ngSubmit)="saveSchema()"> |
<ng-container title> |
||||
<div class="modal-header"> |
Edit Schema |
||||
<h4 class="modal-title">Edit Schema</h4> |
</ng-container> |
||||
|
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="complete()"> |
<ng-container content> |
||||
<span aria-hidden="true">×</span> |
<div class="form-group"> |
||||
</button> |
<label for="schemaName">Name</label> |
||||
</div> |
|
||||
|
|
||||
<div class="modal-body"> |
|
||||
<div class="form-group"> |
|
||||
<label for="schemaName">Name</label> |
|
||||
|
|
||||
<input type="text" class="form-control" id="schemaName" readonly [ngModel]="schema.name" [ngModelOptions]="{standalone: true}" /> |
<input type="text" class="form-control" id="schemaName" readonly [ngModel]="schema.name" [ngModelOptions]="{standalone: true}" /> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="form-group"> |
<div class="form-group"> |
||||
<label for="schemaLabel">Label</label> |
<label for="schemaLabel">Label</label> |
||||
|
|
||||
<sqx-control-errors for="label" [submitted]="editFormSubmitted"></sqx-control-errors> |
<sqx-control-errors for="label" [submitted]="editFormSubmitted"></sqx-control-errors> |
||||
|
|
||||
<input type="text" class="form-control" id="schemaLabel" formControlName="label" /> |
<input type="text" class="form-control" id="schemaLabel" formControlName="label" /> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="form-group"> |
<div class="form-group"> |
||||
<label for="schemaHints">Hints</label> |
<label for="schemaHints">Hints</label> |
||||
|
|
||||
<sqx-control-errors for="hints" [submitted]="editFormSubmitted"></sqx-control-errors> |
<sqx-control-errors for="hints" [submitted]="editFormSubmitted"></sqx-control-errors> |
||||
|
|
||||
<textarea type="text" class="form-control" id="schemaHints" formControlName="hints" rows="4"></textarea> |
<textarea type="text" class="form-control" id="schemaHints" formControlName="hints" rows="4"></textarea> |
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<div class="modal-footer"> |
|
||||
<div class="clearfix"> |
|
||||
<button type="reset" class="float-left btn btn-secondary" (click)="complete()" [disabled]="editFormSubmitted">Cancel</button> |
|
||||
<button type="submit" class="float-right btn btn-primary">Save</button> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
</form> |
</ng-container> |
||||
</div> |
|
||||
</div> |
<ng-container footer> |
||||
|
<button type="reset" class="float-left btn btn-secondary" (click)="complete()" [disabled]="editFormSubmitted">Cancel</button> |
||||
|
<button type="submit" class="float-right btn btn-primary">Save</button> |
||||
|
</ng-container> |
||||
|
</sqx-modal-dialog> |
||||
|
</form> |
||||
@ -1,38 +1,30 @@ |
|||||
<div class="modal-dialog modal-lg"> |
<form [formGroup]="editForm.form" (ngSubmit)="saveSchema()"> |
||||
<div class="modal-content"> |
<sqx-modal-dialog (close)="complete()"> |
||||
<form [formGroup]="editForm" (ngSubmit)="saveSchema()"> |
<ng-container title> |
||||
<div class="modal-header"> |
Scripts |
||||
<h4 class="modal-title">Scripts</h4> |
</ng-container> |
||||
|
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="complete()"> |
<ng-container tabs> |
||||
<span aria-hidden="true">×</span> |
<ul class="nav nav-tabs2"> |
||||
</button> |
<li class="nav-item" *ngFor="let script of editForm.form.controls | sqxKeys"> |
||||
</div> |
<a class="nav-link" [class.active]="selectedField === script" (click)="selectField(script)">{{script.substr(6)}}</a> |
||||
|
</li> |
||||
<div class="modal-tabs clearfix"> |
</ul> |
||||
<ul class="nav nav-tabs2"> |
</ng-container> |
||||
<li class="nav-item" *ngFor="let script of scripts"> |
|
||||
<a class="nav-link" [class.active]="selectedField === 'script' + script" (click)="selectField('script' + script)">{{script}}</a> |
|
||||
</li> |
|
||||
</ul> |
|
||||
</div> |
|
||||
|
|
||||
<div class="modal-body"> |
<ng-container content> |
||||
<div class="form-group"> |
<div class="form-group"> |
||||
<div *ngFor="let script of scripts"> |
<div *ngFor="let script of editForm.form.controls | sqxKeys"> |
||||
<div *ngIf="selectedField === 'script' + script"> |
<div *ngIf="selectedField === script"> |
||||
<sqx-jscript-editor name="script" [formControlName]="'script' + script"></sqx-jscript-editor> |
<sqx-jscript-editor name="script" [formControlName]="script"></sqx-jscript-editor> |
||||
</div> |
|
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
</ng-container> |
||||
|
|
||||
<div class="modal-footer"> |
<ng-container footer> |
||||
<div class="clearfix"> |
<button type="reset" class="float-left btn btn-secondary" (click)="complete()" [disabled]="editFormSubmitted">Cancel</button> |
||||
<button type="reset" class="float-left btn btn-secondary" (click)="complete()" [disabled]="editFormSubmitted">Cancel</button> |
<button type="submit" class="float-right btn btn-primary">Save</button> |
||||
<button type="submit" class="float-right btn btn-primary">Save</button> |
</ng-container> |
||||
</div> |
</sqx-modal-dialog> |
||||
</div> |
</form> |
||||
</form> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|||||
@ -1,51 +1,49 @@ |
|||||
<div class="modal-dialog"> |
<form [formGroup]="createForm.form" (ngSubmit)="createSchema()"> |
||||
<div class="modal-content"> |
<sqx-modal-dialog (close)="complete()" [large]="false"> |
||||
<form [formGroup]="createForm" (ngSubmit)="createSchema()"> |
<ng-container title> |
||||
<div class="modal-header"> |
<ng-container *ngIf="import; else noImport"> |
||||
<h4 class="modal-title" *ngIf="import">Clone Schema</h4> |
Clone Schema |
||||
<h4 class="modal-title" *ngIf="!import">Create Schema</h4> |
</ng-container> |
||||
|
<ng-template #noImport> |
||||
|
Create Schema |
||||
|
</ng-template> |
||||
|
</ng-container> |
||||
|
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="complete()"> |
<ng-container content> |
||||
<span aria-hidden="true">×</span> |
<ng-container *ngIf="createForm.error | async; let error"> |
||||
</button> |
<div class="form-alert form-alert-error" [innerHTML]="error"></div> |
||||
|
</ng-container> |
||||
|
|
||||
|
<div class="form-group"> |
||||
|
<label for="schemaName">Name</label> |
||||
|
|
||||
|
<sqx-control-errors for="name" submitOnly="true" [submitted]="createForm.submitted | async"></sqx-control-errors> |
||||
|
|
||||
|
<input type="text" class="form-control" id="schemaName" formControlName="name" autocomplete="off" sqxLowerCaseInput sqxFocusOnInit /> |
||||
|
|
||||
|
<small class="form-text text-muted"> |
||||
|
The schema name becomes part of the api url,<br /> e.g {{apiUrl.buildUrl("api/content/")}}{{appsState.appName}}/<b>{{createForm.schemaName | async}}</b>/. |
||||
|
</small> |
||||
|
<small class="form-text text-muted"> |
||||
|
It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later. |
||||
|
</small> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="modal-body"> |
<div class="form-group clearfix"> |
||||
<div *ngIf="createFormError"> |
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button> |
||||
<div class="form-alert form-alert-error" [innerHTML]="createFormError"></div> |
<button type="submit" class="float-right btn btn-success">Create</button> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="form-group"> |
<div> |
||||
<label for="schemaName">Name</label> |
<button class="btn btn-sm btn-link" (click)="toggleImport()" [class.hidden]="showImport"> |
||||
|
Import schema |
||||
<sqx-control-errors for="name" submitOnly="true" [submitted]="createFormSubmitted"></sqx-control-errors> |
</button> |
||||
|
<button class="btn btn-sm btn-link" (click)="toggleImport()" [class.hidden]="!showImport"> |
||||
<input type="text" class="form-control" id="schemaName" formControlName="name" autocomplete="off" sqxLowerCaseInput sqxFocusOnInit /> |
Hide |
||||
|
</button> |
||||
<small class="form-text text-muted"> |
|
||||
The schema name becomes part of the api url,<br /> e.g {{apiUrl.buildUrl("api/content/")}}{{appsState.appName}}/<b>{{schemaName | async}}</b>/. |
<sqx-json-editor *ngIf="showImport" formControlName="import"></sqx-json-editor> |
||||
</small> |
|
||||
<small class="form-text text-muted"> |
|
||||
It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later. |
|
||||
</small> |
|
||||
</div> |
|
||||
|
|
||||
<div class="form-group clearfix"> |
|
||||
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button> |
|
||||
<button type="submit" class="float-right btn btn-success">Create</button> |
|
||||
</div> |
|
||||
|
|
||||
<div> |
|
||||
<button class="btn btn-sm btn-link" (click)="toggleImport()" [class.hidden]="showImport"> |
|
||||
Import schema |
|
||||
</button> |
|
||||
<button class="btn btn-sm btn-link" (click)="toggleImport()" [class.hidden]="!showImport"> |
|
||||
Hide |
|
||||
</button> |
|
||||
|
|
||||
<sqx-json-editor *ngIf="showImport" formControlName="import"></sqx-json-editor> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
</form> |
</ng-container> |
||||
</div> |
</sqx-modal-dialog> |
||||
</div> |
</form> |
||||
@ -1,64 +1,54 @@ |
|||||
<sqx-title message="{app} | Schemas" parameter1="app" [value1]="appsState.appName"></sqx-title> |
<sqx-title message="{app} | Schemas" parameter1="app" [value1]="appsState.appName"></sqx-title> |
||||
|
|
||||
<sqx-panel theme="dark" desiredWidth="30rem"> |
<sqx-panel theme="dark" desiredWidth="30rem" showSecondHeader="true"> |
||||
<div class="panel-header"> |
<ng-container title> |
||||
<div class="panel-title-row"> |
Schemas |
||||
<h3 class="panel-title"><i class="icon-schemas"></i> Schemas</h3> |
</ng-container> |
||||
</div> |
|
||||
|
<ng-container secondHeader> |
||||
<a class="panel-close" sqxParentLink isLazyLoaded="true"> |
<sqx-shortcut keys="ctrl+shift+g" (trigger)="addSchemaDialog.show()"></sqx-shortcut> |
||||
<i class="icon-close"></i> |
<sqx-shortcut keys="ctrl+shift+f" (trigger)="inputFind.focus()"></sqx-shortcut> |
||||
</a> |
|
||||
|
<button class="btn btn-success subheader-button" (click)="createSchema(null)" title="New Schema (CTRL + SHIFT + G)"> |
||||
<div class="panel-header-row"> |
<i class="icon-plus"></i> |
||||
<sqx-shortcut keys="ctrl+shift+g" (trigger)="addSchemaDialog.show()"></sqx-shortcut> |
</button> |
||||
<sqx-shortcut keys="ctrl+shift+f" (trigger)="inputFind.focus()"></sqx-shortcut> |
|
||||
|
<div class="search-form"> |
||||
<button class="btn btn-success subheader-button" (click)="createSchema(null)" title="New Schema (CTRL + SHIFT + G)"> |
<input class="form-control form-control-dark" #inputFind [formControl]="schemasFilter" placeholder="Search for schemas..." /> |
||||
<i class="icon-plus"></i> |
|
||||
</button> |
<i class="icon-search"></i> |
||||
|
|
||||
<div class="search-form"> |
|
||||
<input class="form-control form-control-dark" #inputFind [formControl]="schemasFilter" placeholder="Search for schemas..." /> |
|
||||
|
|
||||
<i class="icon-search"></i> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
</div> |
</ng-container> |
||||
|
|
||||
<div class="panel-main"> |
<ng-container content> |
||||
<div class="panel-content"> |
<ul class="nav nav-panel nav-dark nav-dark-bordered flex-column"> |
||||
<ul class="nav nav-panel nav-dark nav-dark-bordered flex-column"> |
<li class="nav-item" *ngFor="let schema of schemasFiltered | async; trackBy: schemasState.trackBySchema"> |
||||
<li class="nav-item" *ngFor="let schema of schemasFiltered | async; trackBy: schemasState.trackBySchema"> |
<a class="nav-link" [routerLink]="[schema.name]" routerLinkActive="active"> |
||||
<a class="nav-link" [routerLink]="[schema.name]" routerLinkActive="active"> |
<div class="row"> |
||||
<div class="row"> |
<div class="col col-4"> |
||||
<div class="col col-4"> |
<span class="schema-name">{{schema.displayName}}</span> |
||||
<span class="schema-name">{{schema.displayName}}</span> |
|
||||
</div> |
|
||||
<div class="col col-4"> |
|
||||
<span class="schema-user"> |
|
||||
<i class="icon-user"></i> {{schema.lastModifiedBy | sqxUserNameRef}} |
|
||||
</span> |
|
||||
</div> |
|
||||
<div class="col col-4 schema-modified"> |
|
||||
<small class="item-modified">{{schema.lastModified | sqxFromNow}}</small> |
|
||||
|
|
||||
<span class="item-published" [class.unpublished]="!schema.isPublished"></span> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
</a> |
<div class="col col-4"> |
||||
</li> |
<span class="schema-user"> |
||||
</ul> |
<i class="icon-user"></i> {{schema.lastModifiedBy | sqxUserNameRef}} |
||||
</div> |
</span> |
||||
</div> |
</div> |
||||
|
<div class="col col-4 schema-modified"> |
||||
|
<small class="item-modified">{{schema.lastModified | sqxFromNow}}</small> |
||||
|
|
||||
|
<span class="item-published" [class.unpublished]="!schema.isPublished"></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</a> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</ng-container> |
||||
</sqx-panel> |
</sqx-panel> |
||||
|
|
||||
<div class="modal" *sqxModalView="addSchemaDialog;onRoot:true" @fade> |
<ng-container *sqxModalView="addSchemaDialog;onRoot:true"> |
||||
<div class="modal-backdrop"></div> |
|
||||
|
|
||||
<sqx-schema-form [import]="import" |
<sqx-schema-form [import]="import" |
||||
(completed)="addSchemaDialog.hide()"> |
(completed)="addSchemaDialog.hide()"> |
||||
</sqx-schema-form> |
</sqx-schema-form> |
||||
</div> |
</ng-container> |
||||
|
|
||||
<router-outlet></router-outlet> |
<router-outlet></router-outlet> |
||||
@ -0,0 +1,31 @@ |
|||||
|
<div class="modal" @fade> |
||||
|
<div class="modal-backdrop"></div> |
||||
|
|
||||
|
<div class="modal-dialog {{large ? 'modal-lg' : ''}}"> |
||||
|
<div class="modal-content"> |
||||
|
<div class="modal-header"> |
||||
|
<h4 class="modal-title"> |
||||
|
<ng-content select=[title]></ng-content> |
||||
|
</h4> |
||||
|
|
||||
|
<button type="button" class="close" (click)="close.emit()"> |
||||
|
<span aria-hidden="true">×</span> |
||||
|
</button> |
||||
|
</div> |
||||
|
|
||||
|
<div class="modal-tabs clearfix" #tabsElement [hidden]="!showTabs"> |
||||
|
<ng-content select=[tabs]></ng-content> |
||||
|
</div> |
||||
|
|
||||
|
<div class="modal-body"> |
||||
|
<ng-content select=[content]></ng-content> |
||||
|
</div> |
||||
|
|
||||
|
<div class="modal-footer" [hidden]="!showFooter"> |
||||
|
<div class="clearfix" #footerElement> |
||||
|
<ng-content select=[footer]></ng-content> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,6 @@ |
|||||
|
@import '_mixins'; |
||||
|
@import '_vars'; |
||||
|
|
||||
|
.modal { |
||||
|
display: block; |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; |
||||
|
|
||||
|
import { fadeAnimation } from './../animations'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-modal-dialog', |
||||
|
styleUrls: ['./modal-dialog.component.scss'], |
||||
|
templateUrl: './modal-dialog.component.html', |
||||
|
animations: [ |
||||
|
fadeAnimation |
||||
|
], |
||||
|
changeDetection: ChangeDetectionStrategy.Default |
||||
|
}) |
||||
|
export class ModalDialogComponent implements AfterViewInit { |
||||
|
@Input() |
||||
|
public showClose = true; |
||||
|
|
||||
|
@Input() |
||||
|
public large = true; |
||||
|
|
||||
|
@Output() |
||||
|
public close = new EventEmitter(); |
||||
|
|
||||
|
@ViewChild('tabsElement') |
||||
|
public tabsElement: ElementRef; |
||||
|
|
||||
|
@ViewChild('footerElement') |
||||
|
public footerElement: ElementRef; |
||||
|
|
||||
|
public showTabs = false; |
||||
|
public showFooter = false; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly changeDetector: ChangeDetectorRef |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public ngAfterViewInit() { |
||||
|
this.showTabs = this.tabsElement.nativeElement.children.length > 0; |
||||
|
this.showFooter = this.footerElement.nativeElement.children.length > 0; |
||||
|
|
||||
|
this.changeDetector.detectChanges(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<div class="grid-footer clearfix" *ngIf="pager && pager.numberOfItems > 0"> |
||||
|
<div class="float-right pagination"> |
||||
|
<span class="pagination-text">{{pager.itemFirst}}-{{pager.itemLast}} of {{pager.numberOfItems}}</span> |
||||
|
|
||||
|
<button class="btn btn-link btn-secondary pagination-button" [disabled]="!pager.canGoPrev" (click)="prev.emit()"> |
||||
|
<i class="icon-angle-left"></i> |
||||
|
</button> |
||||
|
<button class="btn btn-link btn-secondary pagination-button" [disabled]="!pager.canGoNext" (click)="next.emit()"> |
||||
|
<i class="icon-angle-right"></i> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,2 @@ |
|||||
|
@import '_mixins'; |
||||
|
@import '_vars'; |
||||
@ -0,0 +1,26 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
||||
|
|
||||
|
import { Pager } from './../internal'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-pager', |
||||
|
styleUrls: ['./pager.component.scss'], |
||||
|
templateUrl: './pager.component.html' |
||||
|
}) |
||||
|
export class PagerComponent { |
||||
|
@Input() |
||||
|
public pager: Pager; |
||||
|
|
||||
|
@Output() |
||||
|
public next = new EventEmitter(); |
||||
|
|
||||
|
@Output() |
||||
|
public prev = new EventEmitter(); |
||||
|
} |
||||
@ -1,2 +1,9 @@ |
|||||
@import '_mixins'; |
@import '_mixins'; |
||||
@import '_vars'; |
@import '_vars'; |
||||
|
|
||||
|
.panel-header { |
||||
|
&.large { |
||||
|
min-height: 8rem; |
||||
|
max-height: 8rem; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { AbstractControl } from '@angular/forms'; |
||||
|
import { BehaviorSubject, Observable } from 'rxjs'; |
||||
|
|
||||
|
import { ErrorDto } from './utils/error'; |
||||
|
|
||||
|
export interface FormState { |
||||
|
submitted: boolean; |
||||
|
|
||||
|
error?: string; |
||||
|
} |
||||
|
|
||||
|
export class Form<T extends AbstractControl> { |
||||
|
private readonly state = new State<FormState>({ submitted: false }); |
||||
|
|
||||
|
public submitted = |
||||
|
this.state.changes.map(s => s.submitted); |
||||
|
|
||||
|
public error = |
||||
|
this.state.changes.map(s => s.error); |
||||
|
|
||||
|
constructor( |
||||
|
public readonly form: T |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public load(value: any) { |
||||
|
this.state.next({ submitted: false, error: null }); |
||||
|
|
||||
|
this.form.reset(value); |
||||
|
} |
||||
|
|
||||
|
public submit(): any | null { |
||||
|
this.state.next({ submitted: true }); |
||||
|
|
||||
|
if (this.form.valid) { |
||||
|
this.form.disable(); |
||||
|
|
||||
|
return this.form.value; |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public submitCompleted() { |
||||
|
this.state.next({ submitted: false, error: null }); |
||||
|
|
||||
|
this.form.enable(); |
||||
|
} |
||||
|
|
||||
|
public submitFailed(error?: string | ErrorDto) { |
||||
|
this.state.next({ submitted: false, error: this.getError(error) }); |
||||
|
|
||||
|
this.form.enable(); |
||||
|
} |
||||
|
|
||||
|
private getError(error?: string | ErrorDto) { |
||||
|
if (error instanceof ErrorDto) { |
||||
|
return error.displayMessage; |
||||
|
} else { |
||||
|
return error; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export class State<T extends {}> { |
||||
|
private readonly state: BehaviorSubject<T>; |
||||
|
|
||||
|
public get changes(): Observable<T> { |
||||
|
return this.state; |
||||
|
} |
||||
|
|
||||
|
public get snapshot() { |
||||
|
return this.state.value; |
||||
|
} |
||||
|
|
||||
|
constructor(state: T) { |
||||
|
this.state = new BehaviorSubject(state); |
||||
|
} |
||||
|
|
||||
|
public next(update: ((v: T) => T) | object) { |
||||
|
if (update instanceof Function) { |
||||
|
this.state.next(update(this.state.value)); |
||||
|
} else { |
||||
|
this.state.next(Object.assign({}, this.snapshot, update)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue