\ No newline at end of file
diff --git a/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.scss b/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.scss
new file mode 100644
index 000000000..fbb752506
--- /dev/null
+++ b/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.scss
@@ -0,0 +1,2 @@
+@import '_vars';
+@import '_mixins';
\ No newline at end of file
diff --git a/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.ts
new file mode 100644
index 000000000..63d85575d
--- /dev/null
+++ b/src/Squidex/app/features/schemas/pages/schema/types/assets-ui.component.ts
@@ -0,0 +1,25 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+import { AssetsFieldPropertiesDto } from 'shared';
+
+@Component({
+ selector: 'sqx-assets-ui',
+ styleUrls: ['assets-ui.component.scss'],
+ templateUrl: 'assets-ui.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AssetsUIComponent {
+ @Input()
+ public editForm: FormGroup;
+
+ @Input()
+ public properties: AssetsFieldPropertiesDto;
+}
\ No newline at end of file
diff --git a/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.html b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.html
new file mode 100644
index 000000000..54887deda
--- /dev/null
+++ b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.html
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.scss b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.scss
new file mode 100644
index 000000000..f9405a205
--- /dev/null
+++ b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.scss
@@ -0,0 +1,10 @@
+@import '_vars';
+@import '_mixins';
+
+.form-check-input {
+ margin: 0;
+}
+
+.form-group {
+ margin-top: .5rem;
+}
\ No newline at end of file
diff --git a/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.ts
new file mode 100644
index 000000000..07d8f2fed
--- /dev/null
+++ b/src/Squidex/app/features/schemas/pages/schema/types/assets-validation.component.ts
@@ -0,0 +1,25 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+
+import { AssetsFieldPropertiesDto } from 'shared';
+
+@Component({
+ selector: 'sqx-assets-validation',
+ styleUrls: ['assets-validation.component.scss'],
+ templateUrl: 'assets-validation.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AssetsValidationComponent {
+ @Input()
+ public editForm: FormGroup;
+
+ @Input()
+ public properties: AssetsFieldPropertiesDto;
+}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/angular/hide-invalid-image.directive.ts b/src/Squidex/app/framework/angular/hide-invalid-image.directive.ts
deleted file mode 100644
index 346c5db0a..000000000
--- a/src/Squidex/app/framework/angular/hide-invalid-image.directive.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Squidex Headless CMS
- *
- * @license
- * Copyright (c) Sebastian Stehle. All rights reserved
- */
-
-import { Directive, ElementRef, HostListener, Renderer } from '@angular/core';
-
-@Directive({
- selector: '[sqxHideInvalidImage]'
-})
-export class HideInvalidImage {
- constructor(
- private readonly elementRef: ElementRef,
- private readonly renderer: Renderer
- ) {
- }
-
- @HostListener('error')
- public onError() {
- this.renderer.setElementStyle(this.elementRef.nativeElement, 'visibility', 'hidden');
- }
-
- @HostListener('load')
- public onLoad() {
- this.renderer.setElementStyle(this.elementRef.nativeElement, 'visibility', 'visible');
- }
-}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/angular/image-source.directive.ts b/src/Squidex/app/framework/angular/image-source.directive.ts
new file mode 100644
index 000000000..f5c33d5b8
--- /dev/null
+++ b/src/Squidex/app/framework/angular/image-source.directive.ts
@@ -0,0 +1,98 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+import { Directive, ElementRef, HostListener, Input, OnChanges, OnInit, Renderer } from '@angular/core';
+
+import { MathHelper } from './../utils/math-helper';
+
+@Directive({
+ selector: '[sqxImageSource]'
+})
+export class ImageSourceComponent implements OnChanges, OnInit {
+ private retries = 0;
+ private query = MathHelper.guid();
+
+ @Input('sqxImageSource')
+ public imageSource: string;
+
+ @Input()
+ public retryCount = 10;
+
+ @Input()
+ public parent: any = null;
+
+ constructor(
+ private readonly elementRef: ElementRef,
+ private readonly renderer: Renderer
+ ) {
+ }
+
+ public ngOnChanges() {
+ this.retries = 0;
+
+ this.setImageSource();
+ }
+
+ public ngOnInit() {
+ if (this.parent === null) {
+ this.parent = this.elementRef.nativeElement.parentElement;
+ }
+
+ this.resize(this.parent);
+
+ this.renderer.listen(this.parent, 'resize', () => {
+ this.resize(this.parent);
+ });
+ }
+
+ @HostListener('error')
+ public onError() {
+ this.renderer.setElementStyle(this.elementRef.nativeElement, 'visibility', 'hidden');
+
+ this.retryLoadingImage();
+ }
+
+ @HostListener('resize')
+ public onResize() {
+ this.setImageSource();
+ }
+
+ @HostListener('load')
+ public onLoad() {
+ this.renderer.setElementStyle(this.elementRef.nativeElement, 'visibility', 'visible');
+ }
+
+ private resize(parent: any) {
+ const size = parent.getBoundingClientRect();
+
+ this.renderer.setElementStyle(this.elementRef.nativeElement, 'width', size.width + 'px');
+ this.renderer.setElementStyle(this.elementRef.nativeElement, 'height', size.height + 'px');
+ }
+
+ private setImageSource() {
+ const size = this.elementRef.nativeElement.getBoundingClientRect();
+
+ const w = Math.round(size.width);
+ const h = Math.round(size.height);
+
+ const source = `${this.imageSource}&width=${w}&height=${h}&mode=Crop&q=${this.query}`;
+
+ this.renderer.setElementAttribute(this.elementRef.nativeElement, 'src', source);
+ }
+
+ private retryLoadingImage() {
+ this.retries++;
+
+ if (this.retries <= 10) {
+ setTimeout(() => {
+ this.query = MathHelper.guid();
+
+ this.setImageSource();
+ }, this.retries * 1000);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/declarations.ts b/src/Squidex/app/framework/declarations.ts
index 8d313b8a6..3dd5c2837 100644
--- a/src/Squidex/app/framework/declarations.ts
+++ b/src/Squidex/app/framework/declarations.ts
@@ -17,8 +17,8 @@ export * from './angular/file-drop.directive';
export * from './angular/focus-on-change.directive';
export * from './angular/focus-on-init.directive';
export * from './angular/geolocation-editor.component';
-export * from './angular/hide-invalid-image.directive';
export * from './angular/http-utils';
+export * from './angular/image-source.directive';
export * from './angular/indeterminate-value.directive';
export * from './angular/json-editor.component';
export * from './angular/lowercase-input.directive';
diff --git a/src/Squidex/app/framework/module.ts b/src/Squidex/app/framework/module.ts
index 3e588a893..26c737449 100644
--- a/src/Squidex/app/framework/module.ts
+++ b/src/Squidex/app/framework/module.ts
@@ -27,7 +27,7 @@ import {
FocusOnInitDirective,
FromNowPipe,
GeolocationEditorComponent,
- HideInvalidImage,
+ ImageSourceComponent,
IndeterminateValueDirective,
JsonEditorComponent,
LocalStoreService,
@@ -81,7 +81,7 @@ import {
FocusOnInitDirective,
FromNowPipe,
GeolocationEditorComponent,
- HideInvalidImage,
+ ImageSourceComponent,
IndeterminateValueDirective,
JsonEditorComponent,
LowerCaseInputDirective,
@@ -119,7 +119,7 @@ import {
FocusOnInitDirective,
FromNowPipe,
GeolocationEditorComponent,
- HideInvalidImage,
+ ImageSourceComponent,
IndeterminateValueDirective,
JsonEditorComponent,
LowerCaseInputDirective,
diff --git a/src/Squidex/app/shared/components/assets-editor.component.html b/src/Squidex/app/shared/components/assets-editor.component.html
new file mode 100644
index 000000000..9f4ab6c31
--- /dev/null
+++ b/src/Squidex/app/shared/components/assets-editor.component.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/assets-editor.component.scss b/src/Squidex/app/shared/components/assets-editor.component.scss
new file mode 100644
index 000000000..34522e336
--- /dev/null
+++ b/src/Squidex/app/shared/components/assets-editor.component.scss
@@ -0,0 +1,8 @@
+@import '_vars';
+@import '_mixins';
+
+.assets {
+ &-container {
+ border: 1px solid $color-input;
+ }
+}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/assets-editor.component.ts b/src/Squidex/app/shared/components/assets-editor.component.ts
new file mode 100644
index 000000000..45dfc523c
--- /dev/null
+++ b/src/Squidex/app/shared/components/assets-editor.component.ts
@@ -0,0 +1,44 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+import { Component, forwardRef } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+
+const NOOP = () => { /* NOOP */ };
+
+export const SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
+ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AssetsEditorComponent), multi: true
+};
+
+@Component({
+ selector: 'sqx-assets-editor',
+ styleUrls: ['./assets-editor.component.scss'],
+ templateUrl: './assets-editor.component.html',
+ providers: [SQX_ASSETS_EDITOR_CONTROL_VALUE_ACCESSOR]
+})
+export class AssetsEditorComponent implements ControlValueAccessor {
+ private changeCallback: (value: any) => void = NOOP;
+ private touchedCallback: () => void = NOOP;
+
+ public isDisabled = false;
+
+ public writeValue(value: any) {
+ // TODO
+ }
+
+ public setDisabledState(isDisabled: boolean): void {
+ this.isDisabled = isDisabled;
+ }
+
+ public registerOnChange(fn: any) {
+ this.changeCallback = fn;
+ }
+
+ public registerOnTouched(fn: any) {
+ this.touchedCallback = fn;
+ }
+}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/declarations.ts b/src/Squidex/app/shared/declarations.ts
index 1987b3040..d761e8726 100644
--- a/src/Squidex/app/shared/declarations.ts
+++ b/src/Squidex/app/shared/declarations.ts
@@ -7,6 +7,7 @@
export * from './components/app-component-base';
export * from './components/app-form.component';
+export * from './components/assets-editor.component';
export * from './components/component-base';
export * from './components/dashboard-link.directive';
export * from './components/help.component';
diff --git a/src/Squidex/app/shared/module.ts b/src/Squidex/app/shared/module.ts
index 8e94bb73e..3f77c49da 100644
--- a/src/Squidex/app/shared/module.ts
+++ b/src/Squidex/app/shared/module.ts
@@ -19,6 +19,7 @@ import {
AppsStoreService,
AppsService,
AppMustExistGuard,
+ AssetsEditorComponent,
AssetsService,
AuthService,
ContentsService,
@@ -49,6 +50,7 @@ import {
],
declarations: [
AppFormComponent,
+ AssetsEditorComponent,
DashboardLinkDirective,
HelpComponent,
HistoryComponent,
@@ -56,6 +58,7 @@ import {
],
exports: [
AppFormComponent,
+ AssetsEditorComponent,
DashboardLinkDirective,
HelpComponent,
HistoryComponent,
diff --git a/src/Squidex/app/shared/services/schemas.service.spec.ts b/src/Squidex/app/shared/services/schemas.service.spec.ts
index fe0087595..bc560e865 100644
--- a/src/Squidex/app/shared/services/schemas.service.spec.ts
+++ b/src/Squidex/app/shared/services/schemas.service.spec.ts
@@ -157,6 +157,14 @@ describe('SchemasService', () => {
properties: {
fieldType: 'Geolocation'
}
+ }, {
+ fieldId: 7,
+ name: 'field7',
+ isHidden: true,
+ isDisabled: true,
+ properties: {
+ fieldType: 'Assets'
+ }
}]
}
})
@@ -181,7 +189,8 @@ describe('SchemasService', () => {
new FieldDto(3, 'field3', true, true, createProperties('Boolean')),
new FieldDto(4, 'field4', true, true, createProperties('DateTime')),
new FieldDto(5, 'field5', true, true, createProperties('Json')),
- new FieldDto(6, 'field6', true, true, createProperties('Geolocation'))
+ new FieldDto(6, 'field6', true, true, createProperties('Geolocation')),
+ new FieldDto(6, 'field6', true, true, createProperties('Assets'))
]));
authService.verifyAll();
diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts
index 79a9a4f7e..6e5b37c6d 100644
--- a/src/Squidex/app/shared/services/schemas.service.ts
+++ b/src/Squidex/app/shared/services/schemas.service.ts
@@ -47,11 +47,14 @@ export function createProperties(fieldType: string, values: Object | null = null
undefined, undefined, undefined, false, false, false, 'DateTime',
undefined, undefined, undefined);
break;
+ case 'Geolocation':
+ properties = new GeolocationFieldPropertiesDto(undefined, undefined, undefined, false, false, false, 'Map');
+ break;
case 'Json':
properties = new JsonFieldPropertiesDto(undefined, undefined, undefined, false, false, false);
break;
- case 'Geolocation':
- properties = new GeolocationFieldPropertiesDto(undefined, undefined, undefined, false, false, false, 'Map');
+ case 'Assets':
+ properties = new AssetsFieldPropertiesDto(undefined, undefined, undefined, false, false, false);
break;
default:
throw 'Invalid properties type';
@@ -190,6 +193,16 @@ export class GeolocationFieldPropertiesDto extends FieldPropertiesDto {
}
}
+export class AssetsFieldPropertiesDto extends FieldPropertiesDto {
+ constructor(label: string | undefined, hints: string | undefined, placeholder: string | undefined,
+ isRequired: boolean,
+ isListField: boolean,
+ isLocalizable: boolean
+ ) {
+ super('Assets', label, hints, placeholder, isRequired, isListField, isLocalizable);
+ }
+}
+
export class JsonFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string | undefined, hints: string | undefined, placeholder: string | undefined,
isRequired: boolean,
diff --git a/src/Squidex/app/shared/utils/file-helper.ts b/src/Squidex/app/shared/utils/file-helper.ts
index 5dac76465..d2913e6a0 100644
--- a/src/Squidex/app/shared/utils/file-helper.ts
+++ b/src/Squidex/app/shared/utils/file-helper.ts
@@ -43,7 +43,7 @@ export module FileHelper {
}
export function assetPreviewUrl(apiUrl: ApiUrlConfig, asset: AssetDto) {
- return apiUrl.buildUrl(`api/assets/${asset.id}?width=230&height=155&mode=Crop&version=${asset.version.value}&q=${MathHelper.guid()}`);
+ return apiUrl.buildUrl(`api/assets/${asset.id}?version=${asset.version.value}`);
}
export function assetInfo(asset: AssetDto): string {
diff --git a/src/Squidex/app/theme/icomoon/demo.html b/src/Squidex/app/theme/icomoon/demo.html
index c34e47b5e..9d09974f4 100644
--- a/src/Squidex/app/theme/icomoon/demo.html
+++ b/src/Squidex/app/theme/icomoon/demo.html
@@ -275,118 +275,6 @@