Browse Source

Reactive UI (#484)

pull/486/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
408879e80f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      frontend/app/features/content/pages/content/content-field.component.html
  2. 13
      frontend/app/features/content/shared/forms/assets-editor.component.html
  3. 13
      frontend/app/features/content/shared/forms/assets-editor.component.ts
  4. 9
      frontend/app/features/content/shared/forms/field-editor.component.html
  5. 3
      frontend/app/features/content/shared/forms/field-editor.component.ts
  6. 10
      frontend/app/features/content/shared/forms/stock-photo-editor.component.html
  7. 13
      frontend/app/features/content/shared/forms/stock-photo-editor.component.ts
  8. 2
      frontend/app/features/content/shared/preview-button.component.ts
  9. 7
      frontend/app/features/content/shared/references/reference-item.component.ts
  10. 10
      frontend/app/features/content/shared/references/references-editor.component.html
  11. 29
      frontend/app/features/content/shared/references/references-editor.component.ts
  12. 6
      frontend/app/features/settings/pages/more/more-page.component.html
  13. 1
      frontend/app/framework/angular/forms/control-errors.component.ts
  14. 3
      frontend/app/framework/angular/forms/editors/autocomplete.component.ts
  15. 1
      frontend/app/framework/angular/forms/editors/checkbox-group.component.ts
  16. 2
      frontend/app/framework/angular/forms/editors/color-picker.component.ts
  17. 7
      frontend/app/framework/angular/forms/editors/dropdown.component.ts
  18. 4
      frontend/app/framework/angular/forms/editors/stars.component.ts
  19. 5
      frontend/app/framework/angular/forms/editors/tag-editor.component.ts
  20. 1
      frontend/app/framework/angular/forms/editors/toggle.component.ts
  21. 8
      frontend/app/framework/angular/forms/file-drop.directive.ts
  22. 3
      frontend/app/framework/angular/modals/dialog-renderer.component.ts
  23. 82
      frontend/app/framework/angular/resized.directive.ts
  24. 1
      frontend/app/framework/declarations.ts
  25. 3
      frontend/app/framework/module.ts
  26. 13
      frontend/app/shared/components/assets/asset.component.html
  27. 6
      frontend/app/shared/components/assets/asset.component.ts
  28. 4
      frontend/app/shared/components/assets/assets-selector.component.ts
  29. 14
      frontend/app/shared/components/forms/geolocation-editor.component.html
  30. 24
      frontend/app/shared/components/forms/geolocation-editor.component.ts
  31. 4
      frontend/app/shared/components/forms/markdown-editor.component.html
  32. 1
      frontend/app/shared/components/forms/markdown-editor.component.ts
  33. 4
      frontend/app/shared/components/forms/references-dropdown.component.ts
  34. 1
      frontend/app/shared/components/forms/references-tags.component.ts
  35. 2
      frontend/app/shared/components/forms/rich-editor.component.html
  36. 2
      frontend/app/shared/components/schema-category.component.ts
  37. 7
      frontend/app/shell/pages/internal/profile-menu.component.ts
  38. 6
      frontend/package-lock.json
  39. 1
      frontend/package.json

6
frontend/app/features/content/pages/content/content-field.component.html

@ -25,7 +25,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="fieldForm.controls[language.iso2Code]">
</sqx-field-editor>
</div>
@ -38,7 +37,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="selectedFormControl">
</sqx-field-editor>
</ng-template>
@ -51,7 +49,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="selectedFormControl">
</sqx-field-editor>
</ng-template>
@ -81,7 +78,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="true"
[control]="fieldFormCompare?.controls[language.iso2Code]">
</sqx-field-editor>
</div>
@ -92,7 +88,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="true"
[control]="selectedFormControlCompare">
</sqx-field-editor>
</ng-template>
@ -103,7 +98,6 @@
[field]="field"
[language]="language"
[languages]="languages"
[isCompact]="!!fieldFormCompare"
[control]="selectedFormControl">
</sqx-field-editor>
</ng-template>

13
frontend/app/features/content/shared/forms/assets-editor.component.html

@ -19,7 +19,10 @@
</div>
</div>
<div class="body">
<div class="body"
(sqxResizeCondition)="setCompact($event)"
[sqxResizeMinWidth]="600"
[sqxResizeMaxWidth]="0">
<ng-container *ngIf="!snapshot.isListView; else listTemplate">
<div class="row no-gutters">
<sqx-asset *ngFor="let file of snapshot.assetFiles" [assetFile]="file"
@ -30,8 +33,7 @@
[asset]="asset"
(update)="notifyOthers(asset)"
[removeMode]="true"
(remove)="removeLoadedAsset(asset)"
[isCompact]="isCompact">
(remove)="removeLoadedAsset(asset)">
</sqx-asset>
</div>
</ng-container>
@ -39,7 +41,8 @@
<ng-template #listTemplate>
<div class="list-view">
<sqx-asset *ngFor="let file of snapshot.assetFiles" [assetFile]="file"
[isListView]="true"
[isListView]="true"
[isCompact]="snapshot.isCompact"
(loadError)="removeLoadingAsset(file)"
(load)="addAsset(file, $event)">
</sqx-asset>
@ -56,7 +59,7 @@
<sqx-asset
[asset]="asset"
[isListView]="true"
[isCompact]="isCompact"
[isCompact]="snapshot.isCompact"
(update)="notifyOthers(asset)"
[removeMode]="true"
(remove)="removeLoadedAsset(asset)">

13
frontend/app/features/content/shared/forms/assets-editor.component.ts

@ -6,7 +6,7 @@
*/
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import {
@ -34,11 +34,17 @@ class AssetUpdated {
}
interface State {
// The uploading files.
assetFiles: ReadonlyArray<File>;
// The assets to render.
assets: ReadonlyArray<AssetDto>;
// True when showing the assets as list.
isListView: boolean;
// True, when width less than 600 pixels.
isCompact?: boolean;
}
@Component({
@ -51,7 +57,6 @@ interface State {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssetsEditorComponent extends StatefulControlComponent<State, ReadonlyArray<string>> implements OnInit {
@Input()
public isCompact = false;
public assetsDialog = new DialogModel();
@ -104,6 +109,10 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, Reado
}));
}
public setCompact(isCompact: boolean) {
this.next(s => ({ ...s, isCompact: isCompact }));
}
public setAssets(assets: ReadonlyArray<AssetDto>) {
this.next(s => ({ ...s, assets }));
}

9
frontend/app/features/content/shared/forms/field-editor.component.html

@ -31,7 +31,7 @@
</sqx-array-editor>
</ng-container>
<ng-container *ngSwitchCase="'Assets'">
<sqx-assets-editor [formControl]="editorControl" [isCompact]="isCompact"></sqx-assets-editor>
<sqx-assets-editor [formControl]="editorControl"></sqx-assets-editor>
</ng-container>
<ng-container *ngSwitchCase="'Boolean'">
<ng-container [ngSwitch]="field.rawProperties.editor">
@ -47,7 +47,7 @@
<sqx-date-time-editor enforceTime="true" [mode]="field.rawProperties.editor" [formControl]="editorControl"></sqx-date-time-editor>
</ng-container>
<ng-container *ngSwitchCase="'Geolocation'">
<sqx-geolocation-editor [isCompact]="isCompact" [formControl]="editorControl"></sqx-geolocation-editor>
<sqx-geolocation-editor [formControl]="editorControl"></sqx-geolocation-editor>
</ng-container>
<ng-container *ngSwitchCase="'Json'">
<sqx-json-editor height="350" [formControl]="editorControl"></sqx-json-editor>
@ -84,8 +84,7 @@
[allowDuplicates]="field.rawProperties.allowDuplicated"
[language]="language"
[languages]="languages"
[schemaIds]="field.rawProperties.schemaIds"
[isCompact]="isCompact">
[schemaIds]="field.rawProperties.schemaIds">
</sqx-references-editor>
</ng-container>
<ng-container *ngSwitchCase="'Dropdown'">
@ -125,7 +124,7 @@
<sqx-markdown-editor [formControl]="editorControl"></sqx-markdown-editor>
</ng-container>
<ng-container *ngSwitchCase="'StockPhoto'">
<sqx-stock-photo-editor [formControl]="editorControl" [isCompact]="isCompact"></sqx-stock-photo-editor>
<sqx-stock-photo-editor [formControl]="editorControl"></sqx-stock-photo-editor>
</ng-container>
<ng-container *ngSwitchCase="'Dropdown'">
<select class="form-control" [formControl]="editorControl">

3
frontend/app/features/content/shared/forms/field-editor.component.ts

@ -41,9 +41,6 @@ export class FieldEditorComponent {
@Input()
public languages: ReadonlyArray<AppLanguageDto>;
@Input()
public isCompact = false;
@Input()
public displaySuffix: string;

10
frontend/app/features/content/shared/forms/stock-photo-editor.component.html

@ -1,5 +1,9 @@
<div class="row no-gutters">
<div class="col-auto col-image" [class.expand]="isCompact">
<div class="row no-gutters"
(sqxResizeCondition)="setCompact($event)"
[sqxResizeMinWidth]="600"
[sqxResizeMaxWidth]="0">
<div class="col-auto col-image" [class.expand]="snapshot.isCompact">
<input class="form-control value" [formControl]="valueControl" readonly />
<button type="button" class="btn btn-text-secondary value-clear" (click)="reset()">
@ -16,7 +20,7 @@
</div>
</ng-template>
</div>
<div class="col pl-4" *ngIf="!isCompact">
<div class="col pl-4" *ngIf="!snapshot.isCompact">
<i class="icon-angle-left icon"></i>
<input class="form-control" [formControl]="stockPhotoSearch" placeholder="Search for Photos by Unsplash" />

13
frontend/app/features/content/shared/forms/stock-photo-editor.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnInit } from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { of } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, shareReplay, startWith, switchMap, tap } from 'rxjs/operators';
@ -19,7 +19,11 @@ import {
} from '@app/shared';
interface State {
// True when loading assets.
isLoading?: boolean;
// True, when width less than 600 pixels.
isCompact?: boolean;
}
export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
@ -36,9 +40,6 @@ export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StockPhotoEditorComponent extends StatefulControlComponent<State, string> implements OnInit {
@Input()
public isCompact = false;
public valueControl = new FormControl('');
public valueThumb =
@ -94,6 +95,10 @@ export class StockPhotoEditorComponent extends StatefulControlComponent<State, s
}
}
public setCompact(isCompact: boolean) {
this.next(s => ({ ...s, isCompact: isCompact }));
}
public selectPhoto(photo: StockPhotoDto) {
if (!this.snapshot.isDisabled) {
this.valueControl.setValue(photo.url);

2
frontend/app/features/content/shared/preview-button.component.ts

@ -18,8 +18,10 @@ import {
} from '@app/shared';
interface State {
// The name of the selected preview config.
previewNameSelected?: string;
// All other preview configs.
previewNamesMore: ReadonlyArray<string>;
}

7
frontend/app/features/content/shared/references/reference-item.component.ts

@ -32,7 +32,10 @@ export class ReferenceItemComponent implements OnChanges {
public isCompact = false;
@Input()
public columnCount = 0;
public isDisabled = false;
@Input()
public columns = 0;
@Input('sqxReferenceItem')
public content: ContentDto;
@ -46,7 +49,7 @@ export class ReferenceItemComponent implements OnChanges {
private updateValues() {
const values = [];
for (let i = 0; i < this.columnCount; i++) {
for (let i = 0; i < this.columns; i++) {
const field = this.content.referenceFields[i];
if (field) {

10
frontend/app/features/content/shared/references/references-editor.component.html

@ -1,4 +1,7 @@
<div class="references-container" [class.disabled]="snapshot.isDisabled">
<div class="references-container" [class.disabled]="snapshot.isDisabled"
(sqxResizeCondition)="setCompact($event)"
[sqxResizeMinWidth]="600"
[sqxResizeMaxWidth]="0">
<ng-container>
<div class="drop-area-container">
<div class="drop-area" (click)="selectorDialog.show()">
@ -17,8 +20,9 @@
cdkDrag
cdkDragLockAxis="y"
[language]="language"
[isCompact]="isCompact"
[columnCount]="snapshot.columnCount"
[columns]="snapshot.columns"
[isCompact]="snapshot.isCompact"
[isDisabled]="snapshot.isDisabled"
(delete)="remove(content)">
<i cdkDragHandle class="icon-drag2 drag-handle"></i>
</tbody>

29
frontend/app/features/content/shared/references/references-editor.component.ts

@ -25,9 +25,14 @@ export const SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The content items to show.
contentItems: ReadonlyArray<ContentDto>;
columnCount: number;
// The maximum number of columns.
columns: number;
// True, when width less than 600 pixels.
isCompact?: boolean;
}
@Component({
@ -49,22 +54,16 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
@Input()
public languages: ReadonlyArray<AppLanguageDto>;
@Input()
public isCompact = false;
@Input()
public allowDuplicates = true;
@Input()
public columnCount = 0;
public selectorDialog = new DialogModel();
constructor(changeDetector: ChangeDetectorRef,
private readonly appsState: AppsState,
private readonly contentsService: ContentsService
) {
super(changeDetector, { contentItems: [], columnCount: 0 });
super(changeDetector, { contentItems: [], columns: 0 });
}
public writeValue(obj: any) {
@ -89,13 +88,13 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
}
public setContentItems(contentItems: ReadonlyArray<ContentDto>) {
let columnCount = 1;
let columns = 1;
for (const content of contentItems) {
columnCount = Math.max(columnCount, content.referenceFields.length);
columns = Math.max(columns, content.referenceFields.length);
}
this.next(s => ({ ...s, contentItems, columnCount }));
this.next(s => ({ ...s, contentItems, columns }));
}
public select(contents: ReadonlyArray<ContentDto>) {
@ -109,7 +108,7 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
}
public remove(content: ContentDto) {
if (content) {
if (content && !this.snapshot.isDisabled) {
this.setContentItems(this.snapshot.contentItems.filter(x => x.id !== content.id));
this.updateValue();
@ -117,7 +116,7 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
}
public sort(event: CdkDragDrop<ReadonlyArray<ContentDto>>) {
if (event) {
if (event && !this.snapshot.isDisabled) {
this.setContentItems(sorted(event));
this.updateValue();
@ -136,6 +135,10 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, R
this.callTouched();
}
public setCompact(isCompact: boolean) {
this.next(s => ({ ...s, isCompact }));
}
public trackByContent(index: number, content: ContentDto) {
return content.id;
}

6
frontend/app/features/settings/pages/more/more-page.component.html

@ -46,9 +46,11 @@
<div class="card-body">
<div class="row">
<div class="col-auto">
<div class="app-image" noDrop="true" onlyImages="true"
<div class="app-image"
(sqxDropFile)="uploadImage($event)"
[sqxDropDisabled]="uploading || !isImageEditable">
[sqxDropDisabled]="uploading || !isImageEditable"
[sqxDropOnlyImages]="true"
[sqxDropNoPaste]="true">
<div class="app-progress" *ngIf="uploading; else notUploading">
<sqx-progress-bar mode="Circle" [value]="uploadProgress"></sqx-progress-bar>
</div>

1
frontend/app/framework/angular/forms/control-errors.component.ts

@ -18,6 +18,7 @@ import {
import { formatError } from './error-formatting';
interface State {
// The error messages to show.
errorMessages: ReadonlyArray<string>;
}

3
frontend/app/framework/angular/forms/editors/autocomplete.component.ts

@ -27,7 +27,10 @@ export const SQX_AUTOCOMPLETE_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The suggested items.
suggestedItems: ReadonlyArray<any>;
// The selected suggest item index.
suggestedIndex: number;
}

1
frontend/app/framework/angular/forms/editors/checkbox-group.component.ts

@ -19,6 +19,7 @@ export const SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The checked values.
checkedValues: ReadonlyArray<string>;
}

2
frontend/app/framework/angular/forms/editors/color-picker.component.ts

@ -19,8 +19,10 @@ export const SQX_COLOR_PICKER_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The current value.
value?: string;
// The foreground color.
foreground: string;
}

7
frontend/app/framework/angular/forms/editors/dropdown.component.ts

@ -21,9 +21,16 @@ export const SQX_DROPDOWN_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The suggested item.
suggestedItems: ReadonlyArray<any>;
// The selected suggested item.
selectedItem: any;
// The selected suggested index.
selectedIndex: number;
// The current search query.
query?: RegExp;
}

4
frontend/app/framework/angular/forms/editors/stars.component.ts

@ -15,9 +15,13 @@ export const SQX_STARS_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The current stars to show.
stars: number;
// The array for rendering the stars.
starsArray: ReadonlyArray<number>;
// The selected value.
value: number | null;
}

5
frontend/app/framework/angular/forms/editors/tag-editor.component.ts

@ -126,11 +126,16 @@ export const SQX_TAG_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
let CACHED_FONT: string;
interface State {
// True, when the item has the focus.
hasFocus: boolean;
// The suggested item.
suggestedItems: ReadonlyArray<TagValue>;
// The index of the selected suggested items.
suggestedIndex: number;
// All available tag values.
items: ReadonlyArray<TagValue>;
}

1
frontend/app/framework/angular/forms/editors/toggle.component.ts

@ -15,6 +15,7 @@ export const SQX_TOGGLE_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The value indicating if something is checked.
isChecked: boolean | null;
}

8
frontend/app/framework/angular/forms/file-drop.directive.ts

@ -27,11 +27,11 @@ export class FileDropDirective {
@Input()
public allowedFiles: ReadonlyArray<string>;
@Input()
@Input('sqxDropOnlyImages')
public onlyImages: boolean;
@Input()
public noDrop: boolean;
@Input('sqxDropNoPaste')
public noPaste: boolean;
@Input('sqxDropDisabled')
public disabled = false;
@ -47,7 +47,7 @@ export class FileDropDirective {
@HostListener('paste', ['$event'])
public onPaste(event: ClipboardEvent) {
if (this.noDrop) {
if (this.noPaste) {
return;
}

3
frontend/app/framework/angular/modals/dialog-renderer.component.ts

@ -19,10 +19,13 @@ import {
} from '@app/framework/internal';
interface State {
// The pending dialog request.
dialogRequest?: DialogRequest | null;
// The list of open notifications.
notifications: ReadonlyArray<Notification>;
// The current tooltip.
tooltip?: Tooltip | null;
}

82
frontend/app/framework/angular/resized.directive.ts

@ -0,0 +1,82 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Directive, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output } from '@angular/core';
import ResizeObserver from 'resize-observer-polyfill';
const entriesMap = new WeakMap();
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
if (entriesMap.has(entry.target)) {
const component = entriesMap.get(entry.target);
component.onResized(entry);
}
}
});
@Directive({
selector: '[sqxResized], [sqxResizeCondition]'
})
export class ResizedDirective implements OnDestroy, OnChanges {
private condition: ((rect: ClientRect) => boolean) | undefined;
private conditionValue = false;
@Input('sqxResizeMinWidth')
public minWidth?: number;
@Input('sqxResizeMaxWidth')
public maxWidth?: number;
@Output('sqxResizeCondition')
public resizeCondition = new EventEmitter<boolean>();
@Output('sqxResized')
public resize = new EventEmitter<ClientRect>();
constructor(
private readonly element: ElementRef
) {
entriesMap.set(element.nativeElement, this);
observer.observe(element.nativeElement);
}
public ngOnChanges() {
const minWidth = parseInt(<any>this.minWidth, 10);
const maxWidth = parseInt(<any>this.maxWidth, 10);
if (minWidth > 0 && maxWidth > 0) {
this.condition = rect => rect.width < minWidth! || rect.width > maxWidth!;
} else if ( maxWidth > 0) {
this.condition = rect => rect.width > maxWidth!;
} else if (minWidth > 0) {
this.condition = rect => rect.width < minWidth!;
} else {
this.condition = undefined;
}
}
public ngOnDestroy() {
observer.unobserve(this.element.nativeElement);
}
public onResized(entry: ResizeObserverEntry) {
if (this.condition) {
const value = this.condition(entry.contentRect);
if (this.conditionValue !== value) {
this.resizeCondition.emit(value);
this.conditionValue = value;
}
} else {
this.resize.emit(entry.contentRect);
}
}
}

1
frontend/app/framework/declarations.ts

@ -66,6 +66,7 @@ export * from './angular/pager.component';
export * from './angular/panel-container.directive';
export * from './angular/panel.component';
export * from './angular/popup-link.directive';
export * from './angular/resized.directive';
export * from './angular/safe-html.pipe';
export * from './angular/scroll-active.directive';
export * from './angular/shortcut.component';

3
frontend/app/framework/module.ts

@ -74,6 +74,7 @@ import {
ParentLinkDirective,
PopupLinkDirective,
ProgressBarComponent,
ResizedDirective,
ResourceLoaderService,
RootViewComponent,
SafeHtmlPipe,
@ -158,6 +159,7 @@ import {
ParentLinkDirective,
PopupLinkDirective,
ProgressBarComponent,
ResizedDirective,
RootViewComponent,
SafeHtmlPipe,
SafeUrlPipe,
@ -233,6 +235,7 @@ import {
PopupLinkDirective,
ProgressBarComponent,
ReactiveFormsModule,
ResizedDirective,
RootViewComponent,
SafeHtmlPipe,
SafeUrlPipe,

13
frontend/app/shared/components/assets/asset.component.html

@ -1,8 +1,11 @@
<ng-container *ngIf="!isListView; else listTemplate">
<div class="card" [class.selectable]="isSelectable" [class.border-primary]="isSelected" (click)="select.emit()"
<div class="card"
(click)="select.emit()"
[class.selectable]="isSelectable"
[class.border-primary]="isSelected"
(sqxDropFile)="updateFile($event)"
[sqxDropDisabled]="!asset || !asset.canUpload"
[noDrop]="true">
[sqxDropNoPaste]="true">
<div class="card-body">
<div class="file-preview" *ngIf="asset && progress === 0">
<span class="file-type" *ngIf="asset.fileType">
@ -88,10 +91,12 @@
</ng-container>
<ng-template #listTemplate>
<div class="table-items-row" [class.selectable]="isSelectable" (click)="select.emit()"
<div class="table-items-row"
(click)="select.emit()"
[class.selectable]="isSelectable"
(sqxDropFile)="updateFile($event)"
[sqxDropDisabled]="!asset || !asset.canUpload"
[noDrop]="true">
[sqxDropNoPaste]="true">
<div class="left-border" [class.hidden]="!isSelectable" [class.selected]="isSelected" ></div>
<ng-container *ngIf="asset && progress === 0">

6
frontend/app/shared/components/assets/asset.component.ts

@ -51,15 +51,15 @@ export class AssetComponent implements OnInit {
@Input()
public removeMode = false;
@Input()
public isCompact = false;
@Input()
public isDisabled = false;
@Input()
public isSelected = false;
@Input()
public isCompact: boolean;
@Input()
public isSelectable = false;

4
frontend/app/shared/components/assets/assets-selector.component.ts

@ -16,9 +16,13 @@ import {
} from '@app/shared/internal';
interface State {
// The selected assets.
selectedAssets: { [id: string]: AssetDto };
// The number of selected items.
selectionCount: number;
// True, when rendering the assets as list.
isListView: boolean;
}

14
frontend/app/shared/components/forms/geolocation-editor.component.html

@ -1,4 +1,8 @@
<div class="editor-container" [class.compact]="isCompact">
<div class="editor-container" [class.compact]="snapshot.isCompact"
(sqxResizeCondition)="setCompact($event)"
[sqxResizeMinWidth]="600"
[sqxResizeMaxWidth]="0">
<form [class.hidden]="snapshot.isMapHidden">
<div class="editor" #editor></div>
@ -7,7 +11,7 @@
<div class="row mt-2">
<form class="col form-inline no-gutters" [formGroup]="geolocationForm" (change)="updateValueByInput()" (ngSubmit)="updateValueByInput()">
<div class="form-group col-auto pr-2" *ngIf="!isCompact">
<div class="form-group col-auto pr-2" *ngIf="!snapshot.isCompact">
<label for="latitude">Lat: </label>
</div>
<div class="form-group pr-2">
@ -16,7 +20,7 @@
<input type="number" class="form-control" id="latitude" formControlName="latitude" step="any" />
</div>
<div class="form-group col-auto pr-2" *ngIf="!isCompact">
<div class="form-group col-auto pr-2" *ngIf="!snapshot.isCompact">
<label for="longitude">Lon: </label>
</div>
<div class="form-group pr-2">
@ -25,8 +29,8 @@
<input type="number" class="form-control" id="longitude" formControlName="longitude" step="any" />
</div>
<div class="form-group col-auto" *ngIf="!isCompact">
<button [class.hidden]="!hasValue" type="reset" class="btn btn-text clear" [disabled]="snapshot.isDisabled" (click)="reset()">Clear</button>
<div class="form-group col-auto" *ngIf="!snapshot.isCompact">
<button [class.hidden]="!hasValue" type="reset" class="btn btn-text clear" [disabled]="snapshot.isDisabled" (click)="clearValue()">Clear</button>
</div>
</form>
<div class="col-auto">

24
frontend/app/shared/components/forms/geolocation-editor.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, ViewChild } from '@angular/core';
import { FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms';
import {
@ -24,13 +24,14 @@ export const SQX_GEOLOCATION_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => GeolocationEditorComponent), multi: true
};
interface Geolocation {
latitude: number;
longitude: number;
}
type Geolocation = { latitude: number; longitude: number; };
interface Snapshot {
interface State {
// True when the map should be hidden.
isMapHidden?: boolean;
// True, when width less than 600 pixels.
isCompact?: boolean;
}
type UpdateOptions = { reset?: boolean; pan?: true; fire?: boolean };
@ -44,7 +45,7 @@ type UpdateOptions = { reset?: boolean; pan?: true; fire?: boolean };
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class GeolocationEditorComponent extends StatefulControlComponent<Snapshot, Geolocation> implements AfterViewInit {
export class GeolocationEditorComponent extends StatefulControlComponent<State, Geolocation> implements AfterViewInit {
private marker: any;
private map: any;
private value: Geolocation | null = null;
@ -71,9 +72,6 @@ export class GeolocationEditorComponent extends StatefulControlComponent<Snapsho
]
});
@Input()
public isCompact: boolean;
@ViewChild('editor', { static: false })
public editor: ElementRef<HTMLElement>;
@ -286,7 +284,7 @@ export class GeolocationEditorComponent extends StatefulControlComponent<Snapsho
});
}
public reset() {
public clearValue() {
this.value = null;
this.updateMarker({ fire: true });
@ -390,4 +388,8 @@ export class GeolocationEditorComponent extends StatefulControlComponent<Snapsho
}
}
}
public setCompact(isCompact: boolean) {
this.next(s => ({ ...s, isCompact: isCompact }));
}
}

4
frontend/app/shared/components/forms/markdown-editor.component.html

@ -1,4 +1,6 @@
<div #container class="drop-container" (sqxDropFile)="insertFiles($event)" [onlyImages]="true">
<div #container class="drop-container"
(sqxDropFile)="insertFiles($event)"
[sqxDropOnlyImages]="true">
<div #inner [class.fullscreen]="snapshot.isFullscreen">
<textarea class="form-control editor" #editor></textarea>
</div>

1
frontend/app/shared/components/forms/markdown-editor.component.ts

@ -27,6 +27,7 @@ export const SQX_MARKDOWN_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// True, when the editor is shown as fullscreen.
isFullscreen: false;
}

4
frontend/app/shared/components/forms/references-dropdown.component.ts

@ -24,9 +24,13 @@ export const SQX_REFERENCES_DROPDOWN_CONTROL_VALUE_ACCESSOR: any = {
};
interface State {
// The referenced content items.
contents: ReadonlyArray<ContentDto>;
// The names of the selected content items for search.
contentNames: ReadonlyArray<ContentName>;
// The name of the selected item.
selectedItem?: ContentName;
}

1
frontend/app/shared/components/forms/references-tags.component.ts

@ -66,6 +66,7 @@ class TagsConverter implements Converter {
}
interface State {
// The tags converter.
converter: TagsConverter;
}

2
frontend/app/shared/components/forms/rich-editor.component.html

@ -1,4 +1,4 @@
<div class="drop-container" (sqxDropFile)="insertFiles($event)" [onlyImages]="true" #container>
<div class="drop-container" (sqxDropFile)="insertFiles($event)" [sqxDropOnlyImages]="true" #container>
<div class="editor" #editor></div>
</div>

2
frontend/app/shared/components/schema-category.component.ts

@ -18,8 +18,10 @@ import {
} from '@app/shared/internal';
interface State {
// The filtered schemas.
filtered: ReadonlyArray<SchemaDto>;
// True when the category is open.
isOpen?: boolean;
}

7
frontend/app/shell/pages/internal/profile-menu.component.ts

@ -17,9 +17,16 @@ import {
} from '@app/shared';
interface State {
// The display name of the user.
profileDisplayName: string;
// The id of the user.
profileId: string;
// The email address of the user.
profileEmail: string;
// The url to the user profile.
profileUrl: string;
}

6
frontend/package-lock.json

@ -11339,6 +11339,12 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
"dev": true
},
"resolve": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",

1
frontend/package.json

@ -90,6 +90,7 @@
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"raw-loader": "3.1.0",
"resize-observer-polyfill": "^1.5.1",
"rimraf": "3.0.0",
"rxjs-tslint": "0.1.7",
"sass-lint": "^1.13.1",

Loading…
Cancel
Save