Browse Source

Started with stateful component.

pull/345/head
Sebastian Stehle 7 years ago
parent
commit
5f154e1485
  1. 2
      src/Squidex/app/features/administration/pages/users/user-page.component.ts
  2. 2
      src/Squidex/app/features/administration/pages/users/users-page.component.html
  3. 2
      src/Squidex/app/features/administration/state/event-consumers.state.ts
  4. 2
      src/Squidex/app/features/administration/state/users.state.ts
  5. 2
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  6. 2
      src/Squidex/app/features/content/shared/contents-selector.component.html
  7. 2
      src/Squidex/app/features/rules/pages/events/rule-events-page.component.html
  8. 9
      src/Squidex/app/framework/angular/code.component.ts
  9. 6
      src/Squidex/app/framework/angular/forms/checkbox-group.component.html
  10. 50
      src/Squidex/app/framework/angular/forms/checkbox-group.component.ts
  11. 14
      src/Squidex/app/framework/angular/forms/code-editor.component.ts
  12. 4
      src/Squidex/app/framework/angular/forms/control-errors.component.html
  13. 55
      src/Squidex/app/framework/angular/forms/control-errors.component.ts
  14. 5
      src/Squidex/app/framework/angular/forms/json-editor.component.ts
  15. 5
      src/Squidex/app/framework/angular/forms/progress-bar.component.ts
  16. 4
      src/Squidex/app/framework/angular/forms/stars.component.html
  17. 71
      src/Squidex/app/framework/angular/forms/stars.component.ts
  18. 6
      src/Squidex/app/framework/angular/forms/toggle.component.html
  19. 53
      src/Squidex/app/framework/angular/forms/toggle.component.ts
  20. 2
      src/Squidex/app/framework/angular/image-source.directive.ts
  21. 6
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.html
  22. 95
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts
  23. 4
      src/Squidex/app/framework/angular/modals/modal-dialog.component.ts
  24. 36
      src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts
  25. 10
      src/Squidex/app/framework/angular/modals/root-view.component.ts
  26. 37
      src/Squidex/app/framework/angular/modals/tooltip.component.ts
  27. 4
      src/Squidex/app/framework/angular/pager.component.html
  28. 20
      src/Squidex/app/framework/angular/pager.component.ts
  29. 9
      src/Squidex/app/framework/angular/panel.component.ts
  30. 3
      src/Squidex/app/framework/angular/pipes/date-time.pipes.ts
  31. 2
      src/Squidex/app/framework/angular/pipes/money.pipe.ts
  32. 2
      src/Squidex/app/framework/angular/pipes/name.pipe.ts
  33. 12
      src/Squidex/app/framework/angular/shortcut.component.spec.ts
  34. 21
      src/Squidex/app/framework/angular/shortcut.component.ts
  35. 58
      src/Squidex/app/framework/angular/stateful.component.ts
  36. 2
      src/Squidex/app/framework/angular/title.component.ts
  37. 38
      src/Squidex/app/framework/angular/user-report.component.ts
  38. 2
      src/Squidex/app/framework/internal.ts
  39. 11
      src/Squidex/app/framework/state.ts
  40. 2
      src/Squidex/app/shared/components/assets-list.component.html
  41. 4
      src/Squidex/app/shared/state/apps.state.ts
  42. 2
      src/Squidex/app/shared/state/assets.state.ts
  43. 2
      src/Squidex/app/shared/state/contents.forms.ts
  44. 2
      src/Squidex/app/shared/state/schemas.state.ts

2
src/Squidex/app/features/administration/pages/users/user-page.component.ts

@ -42,7 +42,7 @@ export class UserPageComponent implements OnDestroy, OnInit {
this.selectedUserSubscription =
this.usersState.selectedUser
.subscribe(selectedUser => {
this.user = selectedUser;
this.user = selectedUser!;
if (selectedUser) {
this.userForm.load(selectedUser.user);

2
src/Squidex/app/features/administration/pages/users/users-page.component.html

@ -81,7 +81,7 @@
</div>
<div class="grid-footer">
<sqx-pager [pager]="usersState.usersPager | async" (prev)="goPrev()" (next)="goNext()"></sqx-pager>
<sqx-pager [pager]="usersState.usersPager | async" (prevPage)="goPrev()" (nextPage)="goNext()"></sqx-pager>
</div>
</ng-container>
</sqx-panel>

2
src/Squidex/app/features/administration/state/event-consumers.state.ts

@ -21,7 +21,7 @@ import { EventConsumerDto, EventConsumersService } from './../services/event-con
interface Snapshot {
eventConsumers: ImmutableArray<EventConsumerDto>;
isLoaded?: false;
isLoaded?: boolean;
}
@Injectable()

2
src/Squidex/app/features/administration/state/users.state.ts

@ -98,7 +98,7 @@ interface Snapshot {
isLoaded?: boolean;
selectedUser?: SnapshotUser;
selectedUser?: SnapshotUser | null;
}
@Injectable()

2
src/Squidex/app/features/content/pages/contents/contents-page.component.html

@ -120,7 +120,7 @@
</div>
<div class="grid-footer">
<sqx-pager [pager]="contentsState.contentsPager | async" (prev)="goPrev()" (next)="goNext()"></sqx-pager>
<sqx-pager [pager]="contentsState.contentsPager | async" (prevPage)="goPrev()" (nextPage)="goNext()"></sqx-pager>
</div>
</ng-container>

2
src/Squidex/app/features/content/shared/contents-selector.component.html

@ -63,7 +63,7 @@
</div>
<div class="grid-footer">
<sqx-pager [pager]="contentsState.contentsPager | async" (prev)="goPrev()" (next)="goNext()"></sqx-pager>
<sqx-pager [pager]="contentsState.contentsPager | async" (prevPage)="goPrev()" (nextPage)="goNext()"></sqx-pager>
</div>
</ng-container>

2
src/Squidex/app/features/rules/pages/events/rule-events-page.component.html

@ -90,7 +90,7 @@
</tbody>
</table>
<sqx-pager [pager]="ruleEventsState.ruleEventsPager | async" (prev)="goPrev()" (next)="goNext()"></sqx-pager>
<sqx-pager [pager]="ruleEventsState.ruleEventsPager | async" (prevPage)="goPrev()" (nextPage)="goNext()"></sqx-pager>
</ng-container>
</sqx-panel>

9
src/Squidex/app/framework/angular/code.component.ts

@ -5,7 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
import { PureComponent } from '@app/framework/internal';
@Component({
selector: 'sqx-code',
@ -13,5 +15,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
templateUrl: './code.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CodeComponent {
export class CodeComponent extends PureComponent {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector);
}
}

6
src/Squidex/app/framework/angular/forms/checkbox-group.component.html

@ -1,9 +1,9 @@
<span class="form-check" *ngFor="let value of values">
<input type="checkbox" class="form-check-input" id="{{control}}{{value}}"
<input type="checkbox" class="form-check-input" id="{{snapshot.controlId}}{{value}}"
(blur)="blur()"
(change)="check($event.target.checked, value)"
[checked]="isChecked(value)"
[disabled]="isDisabled">
[disabled]="snapshot.isDisabled">
<label class="form-check-label" for="{{control}}{{value}}">{{value}}</label>
<label class="form-check-label" for="{{snapshot.controlId}}{{value}}">{{value}}</label>
</span>

50
src/Squidex/app/framework/angular/forms/checkbox-group.component.ts

@ -8,14 +8,22 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Types } from '@app/framework/internal';
import { MathHelper } from '../../utils/math-helper';
import {
MathHelper,
StatefulComponent,
Types
} from '@app/framework/internal';
export const SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CheckboxGroupComponent), multi: true
};
interface State {
checkedValues: string[];
controlId: string;
isDisabled: boolean;
}
@Component({
selector: 'sqx-checkbox-group',
styleUrls: ['./checkbox-group.component.scss'],
@ -23,33 +31,27 @@ export const SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR: any = {
providers: [SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CheckboxGroupComponent implements ControlValueAccessor {
export class CheckboxGroupComponent extends StatefulComponent<State> implements ControlValueAccessor {
private callChange = (v: any) => { /* NOOP */ };
private callTouched = () => { /* NOOP */ };
private checkedValues: string[] = [];
@Input()
public values: string[] = [];
public isDisabled = false;
public control = MathHelper.guid();
constructor(
private readonly changeDetector: ChangeDetectorRef
) {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {
controlId: MathHelper.guid(),
checkedValues: [],
isDisabled: false
});
}
public writeValue(obj: any) {
this.checkedValues = Types.isArrayOfString(obj) ? obj.filter(x => this.values.indexOf(x) >= 0) : [];
this.changeDetector.markForCheck();
this.next({ checkedValues: Types.isArrayOfString(obj) ? obj.filter(x => this.values.indexOf(x) >= 0) : [] });
}
public setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.changeDetector.markForCheck();
this.next({ isDisabled });
}
public registerOnChange(fn: any) {
@ -65,16 +67,20 @@ export class CheckboxGroupComponent implements ControlValueAccessor {
}
public check(isChecked: boolean, value: string) {
let checkedValues = this.snapshot.checkedValues;
if (isChecked) {
this.checkedValues = [value, ...this.checkedValues];
checkedValues = [value, ...checkedValues];
} else {
this.checkedValues = this.checkedValues.filter(x => x !== value);
checkedValues = checkedValues.filter(x => x !== value);
}
this.callChange(this.checkedValues);
this.next({ checkedValues });
this.callChange(checkedValues);
}
public isChecked(value: string) {
return this.checkedValues.indexOf(value) >= 0;
return this.snapshot.checkedValues.indexOf(value) >= 0;
}
}

14
src/Squidex/app/framework/angular/forms/code-editor.component.ts

@ -5,12 +5,16 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { ResourceLoaderService, Types } from '@app/framework/internal';
import {
PureComponent,
ResourceLoaderService,
Types
} from '@app/framework/internal';
declare var ace: any;
@ -25,7 +29,7 @@ export const SQX_JSCRIPT_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
providers: [SQX_JSCRIPT_EDITOR_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CodeEditorComponent implements ControlValueAccessor, AfterViewInit {
export class CodeEditorComponent extends PureComponent implements ControlValueAccessor, AfterViewInit {
private callChange = (v: any) => { /* NOOP */ };
private callTouched = () => { /* NOOP */ };
private valueChanged = new Subject();
@ -40,8 +44,12 @@ export class CodeEditorComponent implements ControlValueAccessor, AfterViewInit
public mode = 'ace/mode/javascript';
constructor(
changeDetector: ChangeDetectorRef,
private readonly resourceLoader: ResourceLoaderService
) {
super(changeDetector);
changeDetector.detach();
}
public writeValue(obj: any) {

4
src/Squidex/app/framework/angular/forms/control-errors.component.html

@ -1,6 +1,6 @@
<div class="errors-container" *ngIf="errorMessages.length > 0" @fade>
<div class="errors-container" *ngIf="snapshot.errorMessages.length > 0" @fade>
<div class="errors">
<span *ngFor="let message of errorMessages">
<span *ngFor="let message of snapshot.errorMessages">
{{message}}
</span>
</div>

55
src/Squidex/app/framework/angular/forms/control-errors.component.ts

@ -7,12 +7,20 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Host, Input, OnChanges, OnDestroy, Optional } from '@angular/core';
import { AbstractControl, FormGroupDirective } from '@angular/forms';
import { merge, Subscription } from 'rxjs';
import { merge } from 'rxjs';
import { fadeAnimation, Types } from '@app/framework/internal';
import {
fadeAnimation,
StatefulComponent,
Types
} from '@app/framework/internal';
import { formatError } from './error-formatting';
interface State {
errorMessages: string[];
}
@Component({
selector: 'sqx-control-errors',
styleUrls: ['./control-errors.component.scss'],
@ -22,10 +30,9 @@ import { formatError } from './error-formatting';
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ControlErrorsComponent implements OnChanges, OnDestroy {
export class ControlErrorsComponent extends StatefulComponent<State> implements OnChanges, OnDestroy {
private displayFieldName: string;
private control: AbstractControl;
private controlSubscription: Subscription | null = null;
private originalMarkAsTouched: any;
@Input()
@ -43,16 +50,20 @@ export class ControlErrorsComponent implements OnChanges, OnDestroy {
@Input()
public submitOnly = false;
public errorMessages: string[] = [];
constructor(
@Optional() @Host() private readonly formGroupDirective: FormGroupDirective,
private readonly changeDetector: ChangeDetectorRef
constructor(changeDetector: ChangeDetectorRef,
@Optional() @Host() private readonly formGroupDirective: FormGroupDirective
) {
super(changeDetector, {
errorMessages: []
});
}
public ngOnDestroy() {
this.unsubscribe();
super.ngOnDestroy();
if (this.control && this.originalMarkAsTouched) {
this.control['markAsTouched'] = this.originalMarkAsTouched;
}
}
public ngOnChanges() {
@ -75,16 +86,16 @@ export class ControlErrorsComponent implements OnChanges, OnDestroy {
}
if (this.control !== control) {
this.unsubscribe();
this.ngOnDestroy();
this.control = control;
if (control) {
this.controlSubscription =
this.observe(
merge(control.valueChanges, control.statusChanges)
.subscribe(() => {
this.createMessages();
});
}));
this.originalMarkAsTouched = this.control.markAsTouched;
@ -101,18 +112,8 @@ export class ControlErrorsComponent implements OnChanges, OnDestroy {
this.createMessages();
}
private unsubscribe() {
if (this.controlSubscription) {
this.controlSubscription.unsubscribe();
}
if (this.control && this.originalMarkAsTouched) {
this.control['markAsTouched'] = this.originalMarkAsTouched;
}
}
private createMessages() {
const errors: string[] = [];
const errorMessages: string[] = [];
if (this.control && this.control.invalid && ((this.control.touched && !this.submitOnly) || this.submitted) && this.control.errors) {
for (let key in <any>this.control.errors) {
@ -120,14 +121,12 @@ export class ControlErrorsComponent implements OnChanges, OnDestroy {
const message = formatError(this.displayFieldName, key, this.control.errors[key], this.control.value, this.errors);
if (message) {
errors.push(message);
errorMessages.push(message);
}
}
}
}
this.errorMessages = errors;
this.changeDetector.markForCheck();
this.next({ errorMessages });
}
}

5
src/Squidex/app/framework/angular/forms/json-editor.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, forwardRef, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
@ -37,9 +37,10 @@ export class JsonEditorComponent implements ControlValueAccessor, AfterViewInit
@ViewChild('editor')
public editor: ElementRef;
constructor(
constructor(changeDetector: ChangeDetectorRef,
private readonly resourceLoader: ResourceLoaderService
) {
changeDetector.detach();
}
public writeValue(obj: any) {

5
src/Squidex/app/framework/angular/forms/progress-bar.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChanges } from '@angular/core';
import * as ProgressBar from 'progressbar.js';
@ -38,10 +38,11 @@ export class ProgressBarComponent implements OnChanges, OnInit {
@Input()
public value = 0;
constructor(
constructor(changeDetector: ChangeDetectorRef,
private readonly element: ElementRef,
private readonly renderer: Renderer2
) {
changeDetector.detach();
}
public ngOnInit() {

4
src/Squidex/app/framework/angular/forms/stars.component.html

@ -4,8 +4,8 @@
</div>
<ng-container *ngIf="maximumStars > 0 && maximumStars <= 15">
<span class="stars" (mouseleave)="stopPreview()" [class.disabled]="isDisabled">
<span class="star" *ngFor="let star of starsArray" (mouseenter)="setPreview(star)" (click)="setValue(star)" [class.selected]="star <= stars"></span>
<span class="stars" (mouseleave)="stopPreview()" [class.disabled]="snapshot.isDisabled">
<span class="star" *ngFor="let star of snapshot.starsArray" (mouseenter)="setPreview(star)" (click)="setValue(star)" [class.selected]="star <= snapshot.stars"></span>
</span>
<button class="btn btn-text" [class.hidden]="!value" (click)="reset()">Clear</button>

71
src/Squidex/app/framework/angular/forms/stars.component.ts

@ -8,12 +8,21 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Types } from '@app/framework/internal';
import { StatefulComponent, Types } from '@app/framework/internal';
export const SQX_STARS_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StarsComponent), multi: true
};
interface State {
isDisabled: boolean;
stars: number;
starsArray: number[];
value: number | null;
}
@Component({
selector: 'sqx-stars',
styleUrls: ['./stars.component.scss'],
@ -21,7 +30,7 @@ export const SQX_STARS_CONTROL_VALUE_ACCESSOR: any = {
providers: [SQX_STARS_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StarsComponent implements ControlValueAccessor {
export class StarsComponent extends StatefulComponent<State> implements ControlValueAccessor {
private callChange = (v: any) => { /* NOOP */ };
private callTouched = () => { /* NOOP */ };
private maximumStarsValue = 5;
@ -33,11 +42,13 @@ export class StarsComponent implements ControlValueAccessor {
if (this.maximumStarsValue !== maxStars) {
this.maximumStarsValue = value;
this.starsArray = [];
const starsArray = [];
for (let i = 1; i <= value; i++) {
this.starsArray.push(i);
starsArray.push(i);
}
this.next({ starsArray });
}
}
@ -45,28 +56,23 @@ export class StarsComponent implements ControlValueAccessor {
return this.maximumStarsValue;
}
public isDisabled = false;
public stars: number;
public starsArray: number[] = [1, 2, 3, 4, 5];
public value: number | null = 1;
constructor(
private readonly changeDetector: ChangeDetectorRef
) {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {
isDisabled: false,
stars: -1,
starsArray: [1, 2, 3, 4, 5],
value: 1
});
}
public writeValue(obj: any) {
this.value = this.stars = Types.isNumber(obj) ? obj : 0;
const value = Types.isNumber(obj) ? obj : 0;
this.changeDetector.markForCheck();
this.next({ stars: value, value });
}
public setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.changeDetector.markForCheck();
this.next({ isDisabled });
}
public registerOnChange(fn: any) {
@ -77,32 +83,31 @@ export class StarsComponent implements ControlValueAccessor {
this.callTouched = fn;
}
public setPreview(value: number) {
if (this.isDisabled) {
public setPreview(stars: number) {
if (this.snapshot.isDisabled) {
return;
}
this.stars = value;
this.next({ stars });
}
public stopPreview() {
if (this.isDisabled) {
if (this.snapshot.isDisabled) {
return;
}
this.stars = this.value || 0;
this.next(s => { s.stars = s.value || 0; });
}
public reset() {
if (this.isDisabled) {
if (this.snapshot.isDisabled) {
return false;
}
if (this.value) {
this.value = null;
this.stars = 0;
if (this.snapshot.value) {
this.next({ stars: -1, value: null });
this.callChange(this.value);
this.callChange(null);
this.callTouched();
}
@ -110,14 +115,14 @@ export class StarsComponent implements ControlValueAccessor {
}
public setValue(value: number) {
if (this.isDisabled) {
if (this.snapshot.isDisabled) {
return false;
}
if (this.value !== value) {
this.value = this.stars = value;
if (this.snapshot.value !== value) {
this.next({ stars: value, value });
this.callChange(this.value);
this.callChange(value);
this.callTouched();
}

6
src/Squidex/app/framework/angular/forms/toggle.component.html

@ -1,6 +1,6 @@
<div class="toggle-container" (click)="changeState($event)"
[class.disabled]="isDisabled"
[class.checked]="isChecked === true"
[class.unchecked]="isChecked === false">
[class.disabled]="snapshot.isDisabled"
[class.checked]="snapshot.isChecked === true"
[class.unchecked]="snapshot.isChecked === false">
<div class="toggle-button"></div>
</div>

53
src/Squidex/app/framework/angular/forms/toggle.component.ts

@ -5,47 +5,48 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import { ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Types } from '@app/framework/internal';
import { StatefulComponent } from '../stateful.component';
export const SQX_TOGGLE_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ToggleComponent), multi: true
};
interface State {
isDisabled: boolean;
isChecked: boolean | null;
}
@Component({
selector: 'sqx-toggle',
styleUrls: ['./toggle.component.scss'],
templateUrl: './toggle.component.html',
providers: [SQX_TOGGLE_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
providers: [SQX_TOGGLE_CONTROL_VALUE_ACCESSOR]
})
export class ToggleComponent implements ControlValueAccessor {
export class ToggleComponent extends StatefulComponent<State> implements ControlValueAccessor {
private callChange = (v: any) => { /* NOOP */ };
private callTouched = () => { /* NOOP */ };
@Input()
public threeStates = false;
public isChecked: boolean | null = null;
public isDisabled = false;
constructor(
private readonly changeDetector: ChangeDetectorRef
) {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {
isChecked: null,
isDisabled: false
});
}
public writeValue(obj: any) {
this.isChecked = Types.isBoolean(obj) ? obj : null;
this.changeDetector.markForCheck();
this.next({ isChecked: Types.isBoolean(obj) ? obj : null });
}
public setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.changeDetector.markForCheck();
this.next({ isDisabled });
}
public registerOnChange(fn: any) {
@ -57,23 +58,27 @@ export class ToggleComponent implements ControlValueAccessor {
}
public changeState(event: MouseEvent) {
if (this.isDisabled) {
let { isDisabled, isChecked } = this.snapshot;
if (isDisabled) {
return;
}
if (this.threeStates && (event.ctrlKey || event.shiftKey)) {
if (this.isChecked) {
this.isChecked = null;
} else if (this.isChecked === null) {
this.isChecked = false;
if (isChecked) {
isChecked = null;
} else if (isChecked === null) {
isChecked = false;
} else {
this.isChecked = true;
isChecked = true;
}
} else {
this.isChecked = !(this.isChecked === true);
isChecked = !(isChecked === true);
}
this.callChange(this.isChecked);
this.next({ isChecked });
this.callChange(isChecked);
this.callTouched();
}
}

2
src/Squidex/app/framework/angular/image-source.directive.ts

@ -7,7 +7,7 @@
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { MathHelper } from './../utils/math-helper';
import { MathHelper } from '@app/framework/internal';
const LAYOUT_CACHE: { [key: string]: { width: number, height: number } } = {};

6
src/Squidex/app/framework/angular/modals/dialog-renderer.component.html

@ -2,11 +2,11 @@
<sqx-modal-dialog *sqxModalView="dialogView;onRoot:true" showClose="false" (closed)="cancel()">
<ng-container title>
{{dialogRequest?.title}}
{{snapshot.dialogRequest?.title}}
</ng-container>
<ng-container content>
{{dialogRequest?.text}}
{{snapshot.dialogRequest?.text}}
</ng-container>
<ng-container footer>
@ -16,7 +16,7 @@
</sqx-modal-dialog>
<div class="notification-container notification-container-{{position}}">
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of notifications" (click)="close(notification)" @fade>
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of snapshot.notifications" (click)="close(notification)" @fade>
<button type="button" class="close" data-dismiss="alert" (closed)="close(notification)">&times;</button>
<span [innerHTML]="notification.message"></span>

95
src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts

@ -5,8 +5,8 @@
* Copyright (c) Sebastian Stehle. All rights r vbeserved
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { timer } from 'rxjs';
import {
DialogModel,
@ -16,6 +16,14 @@ import {
Notification
} from '@app/framework/internal';
import { StatefulComponent } from '../stateful.component';
interface State {
dialogRequest?: DialogRequest | null;
notifications: Notification[];
}
@Component({
selector: 'sqx-dialog-renderer',
styleUrls: ['./dialog-renderer.component.scss'],
@ -25,89 +33,74 @@ import {
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DialogRendererComponent implements OnDestroy, OnInit {
private dialogSubscription: Subscription;
private dialogsSubscription: Subscription;
private notificationsSubscription: Subscription;
public dialogView = new DialogModel();
public dialogRequest: DialogRequest | null = null;
public notifications: Notification[] = [];
export class DialogRendererComponent extends StatefulComponent<State> implements OnInit {
@Input()
public position = 'bottomright';
constructor(
private readonly changeDetector: ChangeDetectorRef,
public dialogView = new DialogModel();
constructor(changeDetector: ChangeDetectorRef,
private readonly dialogs: DialogService
) {
}
public ngOnDestroy() {
this.notificationsSubscription.unsubscribe();
this.dialogSubscription.unsubscribe();
this.dialogsSubscription.unsubscribe();
super(changeDetector, { notifications: [] });
}
public ngOnInit() {
this.dialogSubscription =
this.observe(
this.dialogView.isOpen.subscribe(isOpen => {
if (!isOpen) {
this.cancel();
this.changeDetector.detectChanges();
this.finishRequest(false);
}
});
}));
this.notificationsSubscription =
this.observe(
this.dialogs.notifications.subscribe(notification => {
this.notifications.push(notification);
this.next(state => {
state.notifications = [...state.notifications, notification];
});
if (notification.displayTime > 0) {
setTimeout(() => {
this.observe(timer(notification.displayTime).subscribe(() => {
this.close(notification);
}, notification.displayTime);
}));
}
}));
this.changeDetector.detectChanges();
});
this.dialogsSubscription =
this.observe(
this.dialogs.dialogs
.subscribe(request => {
this.cancel();
this.dialogRequest = request;
this.dialogView.show();
this.changeDetector.detectChanges();
this.next(state => {
state.dialogRequest = request;
});
}));
}
public cancel() {
if (this.dialogRequest) {
this.dialogRequest.complete(false);
this.dialogRequest = null;
this.finishRequest(false);
this.dialogView.hide();
}
}
public confirm() {
if (this.dialogRequest) {
this.dialogRequest.complete(true);
this.dialogRequest = null;
this.finishRequest(true);
this.dialogView.hide();
}
private finishRequest(value: boolean) {
this.next(state => {
if (state.dialogRequest) {
state.dialogRequest.complete(value);
state.dialogRequest = null;
}
});
}
public close(notification: Notification) {
const index = this.notifications.indexOf(notification);
if (index >= 0) {
this.notifications.splice(index, 1);
this.changeDetector.detectChanges();
}
this.next(state => {
state.notifications = state.notifications.filter(n => notification !== n);
});
}
}

4
src/Squidex/app/framework/angular/modals/modal-dialog.component.ts

@ -7,7 +7,7 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { fadeAnimation } from './../animations';
import { fadeAnimation } from '@app/framework/internal';
@Component({
selector: 'sqx-modal-dialog',
@ -16,7 +16,7 @@ import { fadeAnimation } from './../animations';
animations: [
fadeAnimation
],
changeDetection: ChangeDetectionStrategy.Default
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ModalDialogComponent implements AfterViewInit {
@Input()

36
src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts

@ -6,11 +6,13 @@
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { timer } from 'rxjs';
import {
fadeAnimation,
ModalModel,
OnboardingService,
PureComponent,
Types
} from '@app/framework/internal';
@ -23,11 +25,7 @@ import {
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnboardingTooltipComponent implements OnDestroy, OnInit {
private showTimer: any;
private closeTimer: any;
private forMouseDownListener: Function | null;
export class OnboardingTooltipComponent extends PureComponent implements OnDestroy, OnInit {
public tooltipModal = new ModalModel();
@Input()
@ -42,28 +40,23 @@ export class OnboardingTooltipComponent implements OnDestroy, OnInit {
@Input()
public position = 'left';
constructor(
private readonly changeDetector: ChangeDetectorRef,
constructor(changeDetector: ChangeDetectorRef,
private readonly onboardingService: OnboardingService,
private readonly renderer: Renderer2
) {
super(changeDetector);
}
public ngOnDestroy() {
clearTimeout(this.showTimer);
clearTimeout(this.closeTimer);
super.ngOnDestroy();
this.tooltipModal.hide();
if (this.forMouseDownListener) {
this.forMouseDownListener();
this.forMouseDownListener = null;
}
}
public ngOnInit() {
if (this.for && this.helpId && Types.isFunction(this.for.addEventListener)) {
this.showTimer = setTimeout(() => {
this.observe(
timer(this.after).subscribe(() => {
if (this.onboardingService.shouldShow(this.helpId)) {
const forRect = this.for.getBoundingClientRect();
@ -75,23 +68,22 @@ export class OnboardingTooltipComponent implements OnDestroy, OnInit {
if (this.isSameOrParent(fromPoint)) {
this.tooltipModal.show();
this.changeDetector.markForCheck();
this.closeTimer = setTimeout(() => {
this.observe(
timer(10000).subscribe(() => {
this.hideThis();
}, 10000);
}));
this.onboardingService.disable(this.helpId);
}
}
}, this.after);
}));
this.forMouseDownListener =
this.observe(
this.renderer.listen(this.for, 'mousedown', () => {
this.onboardingService.disable(this.helpId);
this.hideThis();
});
}));
}
}

10
src/Squidex/app/framework/angular/modals/root-view.component.ts

@ -5,7 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component, ViewChild, ViewContainerRef } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewChild, ViewContainerRef } from '@angular/core';
import { PureComponent } from '@app/framework/internal';
@Component({
selector: 'sqx-root-view',
@ -13,7 +15,11 @@ import { ChangeDetectionStrategy, Component, ViewChild, ViewContainerRef } from
templateUrl: './root-view.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RootViewComponent {
export class RootViewComponent extends PureComponent {
@ViewChild('element', { read: ViewContainerRef })
public viewContainer: ViewContainerRef;
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector);
}
}

37
src/Squidex/app/framework/angular/modals/tooltip.component.ts

@ -7,9 +7,11 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { ModalModel } from './../../utils/modal-view';
import { fadeAnimation } from './../animations';
import {
fadeAnimation,
ModalModel,
PureComponent
} from '@app/framework/internal';
@Component({
selector: 'sqx-tooltip',
@ -20,10 +22,7 @@ import { fadeAnimation } from './../animations';
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TooltipComponent implements OnDestroy, OnInit {
private targetMouseEnterListener: any;
private targetMouseLeaveListener: any;
export class TooltipComponent extends PureComponent implements OnDestroy, OnInit {
@Input()
public target: any;
@ -32,35 +31,23 @@ export class TooltipComponent implements OnDestroy, OnInit {
public modal = new ModalModel();
constructor(
private readonly changeDetector: ChangeDetectorRef,
constructor(changeDetector: ChangeDetectorRef,
private readonly renderer: Renderer2
) {
}
public ngOnDestroy() {
if (this.targetMouseEnterListener) {
this.targetMouseEnterListener();
}
if (this.targetMouseLeaveListener) {
this.targetMouseLeaveListener();
}
super(changeDetector);
}
public ngOnInit() {
if (this.target) {
this.targetMouseEnterListener =
this.observe(
this.renderer.listen(this.target, 'mouseenter', () => {
this.modal.show();
}));
this.changeDetector.markForCheck();
});
this.targetMouseLeaveListener =
this.observe(
this.renderer.listen(this.target, 'mouseleave', () => {
this.modal.hide();
});
}));
}
}
}

4
src/Squidex/app/framework/angular/pager.component.html

@ -2,10 +2,10 @@
<div class="float-right pagination">
<span class="pagination-text">{{pager.itemFirst}}-{{pager.itemLast}} of {{pager.numberOfItems}}</span>
<button class="btn btn-text-secondary pagination-button" [disabled]="!pager.canGoPrev" (click)="prev.emit()">
<button class="btn btn-text-secondary pagination-button" [disabled]="!pager.canGoPrev" (click)="prevPage.emit()">
<i class="icon-angle-left"></i>
</button>
<button class="btn btn-text-secondary pagination-button" [disabled]="!pager.canGoNext" (click)="next.emit()">
<button class="btn btn-text-secondary pagination-button" [disabled]="!pager.canGoNext" (click)="nextPage.emit()">
<i class="icon-angle-right"></i>
</button>
</div>

20
src/Squidex/app/framework/angular/pager.component.ts

@ -5,9 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
import { Pager } from './../internal';
import { Pager, PureComponent } from '@app/framework/internal';
@Component({
selector: 'sqx-pager',
@ -15,16 +15,20 @@ import { Pager } from './../internal';
templateUrl: './pager.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PagerComponent {
export class PagerComponent extends PureComponent {
@Output()
public nextPage = new EventEmitter();
@Output()
public prevPage = new EventEmitter();
@Input()
public pager: Pager;
@Input()
public hideWhenButtonsDisabled = false;
@Output()
public next = new EventEmitter();
@Output()
public prev = new EventEmitter();
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector);
}
}

9
src/Squidex/app/framework/angular/panel.component.ts

@ -5,9 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { slideRightAnimation } from './animations';
import { PureComponent, slideRightAnimation } from '@app/framework/internal';
import { PanelContainerDirective } from './panel-container.directive';
@ -20,7 +20,7 @@ import { PanelContainerDirective } from './panel-container.directive';
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
export class PanelComponent extends PureComponent implements AfterViewInit, OnDestroy, OnInit {
private styleWidth: string;
public renderWidth = 0;
@ -61,10 +61,11 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
@ViewChild('panel')
public panel: ElementRef<HTMLElement>;
constructor(
constructor(changeDetector: ChangeDetectorRef,
private readonly container: PanelContainerDirective,
private readonly renderer: Renderer2
) {
super(changeDetector);
}
public ngOnDestroy() {

3
src/Squidex/app/framework/angular/pipes/date-time.pipes.ts

@ -7,8 +7,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DateTime } from './../../utils/date-time';
import { Duration } from './../../utils/duration';
import { DateTime, Duration } from '@app/framework/internal';
@Pipe({
name: 'sqxShortDate',

2
src/Squidex/app/framework/angular/pipes/money.pipe.ts

@ -7,7 +7,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { CurrencyConfig, DecimalSeparatorConfig } from './../../configurations';
import { CurrencyConfig, DecimalSeparatorConfig } from '@app/framework/internal';
@Pipe({
name: 'sqxMoney',

2
src/Squidex/app/framework/angular/pipes/name.pipe.ts

@ -7,7 +7,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { StringHelper } from './../../utils/string-helper';
import { StringHelper } from '@app/framework/internal';
@Pipe({
name: 'sqxDisplayName',

12
src/Squidex/app/framework/angular/shortcut.component.spec.ts

@ -18,13 +18,13 @@ describe('ShortcutComponent', () => {
});
it('should instantiate', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
expect(shortcutComponent).toBeDefined();
});
it('should init without keys', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
shortcutComponent.keys = null!;
shortcutComponent.ngOnInit();
@ -33,7 +33,7 @@ describe('ShortcutComponent', () => {
});
it('should destroy without keys', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
shortcutComponent.keys = null!;
shortcutComponent.ngOnDestroy();
@ -42,7 +42,7 @@ describe('ShortcutComponent', () => {
});
it('should raise event when triggered', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
let isTriggered = false;
@ -56,7 +56,7 @@ describe('ShortcutComponent', () => {
});
it('should not raise event when triggered but disabled', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
let isTriggered = false;
@ -71,7 +71,7 @@ describe('ShortcutComponent', () => {
});
it('should not raise event when triggered but destroyed', () => {
const shortcutComponent = new ShortcutComponent(shortcutService, new NgZone({}));
const shortcutComponent = new ShortcutComponent(<any>{}, shortcutService, new NgZone({}));
let isTriggered = false;

21
src/Squidex/app/framework/angular/shortcut.component.ts

@ -5,16 +5,17 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { ShortcutService } from './../services/shortcut.service';
import { PureComponent, ShortcutService } from '@app/framework/internal';
@Component({
selector: 'sqx-shortcut',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
template: ''
})
export class ShortcutComponent implements OnDestroy, OnInit {
export class ShortcutComponent extends PureComponent implements OnDestroy, OnInit {
private lastKeys: string;
@Input()
public keys: string;
@ -24,12 +25,14 @@ export class ShortcutComponent implements OnDestroy, OnInit {
@Output()
public trigger = new EventEmitter();
private lastKeys: string;
constructor(
changeDetector: ChangeDetectorRef,
private readonly shortcutService: ShortcutService,
private readonly zone: NgZone
) {
super(changeDetector);
changeDetector.detach();
}
public ngOnDestroy() {
@ -42,10 +45,10 @@ export class ShortcutComponent implements OnDestroy, OnInit {
this.lastKeys = this.keys;
if (this.lastKeys) {
this.shortcutService.on(this.lastKeys, e => {
this.shortcutService.on(this.lastKeys, () => {
if (!this.disabled) {
this.zone.run(() => {
this.trigger.next(e);
this.trigger.next();
});
}

58
src/Squidex/app/framework/angular/stateful.component.ts

@ -0,0 +1,58 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectorRef, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { Types } from './../utils/types';
import { State } from '../state';
declare type UnsubscribeFunction = () => void;
export abstract class StatefulComponent<T> extends State<T> implements OnDestroy, OnInit {
private subscriptions: (Subscription | UnsubscribeFunction)[] = [];
constructor(
private readonly changeDetector: ChangeDetectorRef,
state: T
) {
super(state);
}
protected observe(subscription: Subscription | UnsubscribeFunction) {
if (subscription) {
this.subscriptions.push(subscription);
}
}
public ngOnInit() {
this.changes.subscribe(() => {
this.changeDetector.detectChanges();
});
}
public ngOnDestroy() {
try {
for (let subscription of this.subscriptions) {
if (Types.isFunction(subscription)) {
subscription();
} else {
subscription.unsubscribe();
}
}
} finally {
this.subscriptions = [];
}
}
}
export abstract class PureComponent extends StatefulComponent<any> {
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {});
}
}

2
src/Squidex/app/framework/angular/title.component.ts

@ -7,7 +7,7 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { TitleService } from './../services/title.service';
import { TitleService } from '@app/framework/internal';
@Component({
selector: 'sqx-title',

38
src/Squidex/app/framework/angular/user-report.component.ts

@ -5,36 +5,36 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { timer } from 'rxjs';
import { UserReportConfig } from './../configurations';
import { ResourceLoaderService } from './../services/resource-loader.service';
import {
PureComponent,
ResourceLoaderService,
UserReportConfig
} from '@app/framework/internal';
@Component({
selector: 'sqx-user-report',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
template: ''
})
export class UserReportComponent implements OnDestroy, OnInit {
private loadingTimer: any;
constructor(config: UserReportConfig, changeDetector: ChangeDetectorRef,
export class UserReportComponent extends PureComponent implements OnDestroy, OnInit {
constructor(changeDetector: ChangeDetectorRef,
private readonly config: UserReportConfig,
private readonly resourceLoader: ResourceLoaderService
) {
changeDetector.detach();
window['_urq'] = window['_urq'] || [];
window['_urq'].push(['initSite', config.siteId]);
}
super(changeDetector);
public ngOnDestroy() {
clearTimeout(this.loadingTimer);
changeDetector.detach();
}
public ngOnInit() {
this.loadingTimer =
setTimeout(() => {
window['_urq'] = window['_urq'] || [];
window['_urq'].push(['initSite', this.config.siteId]);
this.observe(
timer(4000).subscribe(() => {
this.resourceLoader.loadScript('https://cdn.userreport.com/userreport.js');
}, 4000);
}));
}
}

2
src/Squidex/app/framework/internal.ts

@ -35,4 +35,6 @@ export * from './utils/string-helper';
export * from './utils/types';
export * from './utils/version';
export * from './angular/stateful.component';
export * from './configurations';

11
src/Squidex/app/framework/state.ts

@ -15,7 +15,7 @@ import { fullValue} from './angular/forms/forms-helper';
export interface FormState {
submitted: boolean;
error?: string;
error?: string | null;
}
export class Form<T extends AbstractControl> {
@ -136,11 +136,14 @@ export class State<T extends {}> {
this.next(this.initialState);
}
public next(update: ((v: T) => T) | object) {
public next(update: ((v: T) => T | void) | Partial<T>) {
if (Types.isFunction(update)) {
this.state.next(update(this.state.value));
const stateNew = { ...this.snapshot };
const stateUpdated = update(stateNew);
this.state.next(stateUpdated || stateNew);
} else {
this.state.next(Object.assign({}, this.snapshot, update));
this.state.next({ ...this.snapshot, ...update });
}
}
}

2
src/Squidex/app/shared/components/assets-list.component.html

@ -35,4 +35,4 @@
</ng-container>
</div>
<sqx-pager [hideWhenButtonsDisabled]="true" [pager]="state.assetsPager | async" (prev)="goPrev()" (next)="goNext()"></sqx-pager>
<sqx-pager [hideWhenButtonsDisabled]="true" [pager]="state.assetsPager | async" (prevPage)="goPrev()" (nextPage)="goNext()"></sqx-pager>

4
src/Squidex/app/shared/state/apps.state.ts

@ -67,9 +67,9 @@ export class AppsState extends State<Snapshot> {
public load(): Observable<any> {
return this.appsService.getApps().pipe(
tap(dtos => {
tap((dto: AppDto[]) => {
this.next(s => {
const apps = ImmutableArray.of(dtos);
const apps = ImmutableArray.of(dto);
return { ...s, apps };
});

2
src/Squidex/app/shared/state/assets.state.ts

@ -28,7 +28,7 @@ interface Snapshot {
assetsPager: Pager;
assetsQuery?: string;
isLoaded?: false;
isLoaded?: boolean;
}
@Injectable()

2
src/Squidex/app/shared/state/contents.forms.ts

@ -147,7 +147,7 @@ export class FieldValidatorsFactory implements FieldPropertiesVisitor<ValidatorF
public visitNumber(properties: NumberFieldPropertiesDto): ValidatorFn[] {
const validators: ValidatorFn[] = [
ValidatorsEx.betweenLength(properties.minValue, properties.maxValue)
ValidatorsEx.between(properties.minValue, properties.maxValue)
];
if (properties.allowedValues && properties.allowedValues.length > 0) {

2
src/Squidex/app/shared/state/schemas.state.ts

@ -325,7 +325,7 @@ export class SchemasState extends State<Snapshot> {
private replaceSchema(schema: SchemaDto) {
return this.next(s => {
const schemas = s.schemas.replaceBy('id', schema).sortByStringAsc(x => x.displayName);
const selectedSchema = s.selectedSchema && s.selectedSchema.id === schema.id ? schema : s.selectedSchema;
const selectedSchema = Types.is(schema, SchemaDetailsDto) && s.selectedSchema && s.selectedSchema.id === schema.id ? schema : s.selectedSchema;
const categories = buildCategories(s.categories, schemas);

Loading…
Cancel
Save