diff --git a/src/Squidex/app/declarations.d.ts b/src/Squidex/app/declarations.d.ts
index 6ba1c563c..d40cdbd10 100644
--- a/src/Squidex/app/declarations.d.ts
+++ b/src/Squidex/app/declarations.d.ts
@@ -10,9 +10,9 @@ declare module 'pikaday/pikaday';
declare module 'progressbar.js';
declare module 'sortablejs' {
- export default class Sortable {
+ export class Ref {
public destroy(): any;
-
- public static create(element: any, options: any): Sortable;
}
+
+ export function create(element: any, options: any): Ref;
}
diff --git a/src/Squidex/app/features/assets/pages/assets-page.component.ts b/src/Squidex/app/features/assets/pages/assets-page.component.ts
index 9eb1241e4..7a2a9f521 100644
--- a/src/Squidex/app/features/assets/pages/assets-page.component.ts
+++ b/src/Squidex/app/features/assets/pages/assets-page.component.ts
@@ -37,7 +37,7 @@ export class AssetsPageComponent implements OnInit {
private readonly localStore: LocalStoreService,
private readonly uiState: UIState
) {
- this.isListView = this.localStore.get('assetView') === 'List';
+ this.isListView = this.localStore.getBoolean('squidex.assets.list-view');
}
public ngOnInit() {
@@ -77,9 +77,9 @@ export class AssetsPageComponent implements OnInit {
}
public changeView(isListView: boolean) {
- this.localStore.set('assetView', isListView ? 'List' : 'Grid');
-
this.isListView = isListView;
+
+ this.localStore.setBoolean('squidex.assets.list-view', isListView);
}
}
diff --git a/src/Squidex/app/features/content/pages/content/content-field.component.html b/src/Squidex/app/features/content/pages/content/content-field.component.html
index 21083937f..b4213c77f 100644
--- a/src/Squidex/app/features/content/pages/content/content-field.component.html
+++ b/src/Squidex/app/features/content/pages/content/content-field.component.html
@@ -1,23 +1,42 @@
-
1">
-
- 1">
+
+
+
+
-
+
+
+ Please remember to check all languages when you see validation errors.
+
+
+
-
- Please remember to check all languages when you see validation errors.
-
+
+
+
+
+
-
-
+
+
+
+
diff --git a/src/Squidex/app/features/content/pages/content/content-field.component.ts b/src/Squidex/app/features/content/pages/content/content-field.component.ts
index ec7a9d5ad..cf176d979 100644
--- a/src/Squidex/app/features/content/pages/content/content-field.component.ts
+++ b/src/Squidex/app/features/content/pages/content/content-field.component.ts
@@ -15,7 +15,9 @@ import {
EditContentForm,
fieldInvariant,
ImmutableArray,
+ LocalStoreService,
RootFieldDto,
+ SchemaDto,
Types
} from '@app/shared';
@@ -34,6 +36,9 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
@Input()
public fieldForm: FormGroup;
+ @Input()
+ public schema: SchemaDto;
+
@Input()
public language: AppLanguageDto;
@@ -44,13 +49,29 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
public languageChange = new EventEmitter();
public selectedFormControl: AbstractControl;
+ public showAllControls = false;
public isInvalid: Observable;
+ constructor(
+ private readonly localStore: LocalStoreService
+ ) {
+ }
+
public ngOnChanges(changes: SimpleChanges) {
if (changes['fieldForm']) {
this.isInvalid = this.fieldForm.statusChanges.pipe(startWith(this.fieldForm.invalid), map(x => this.fieldForm.invalid));
}
+
+ if (changes['field']) {
+ this.showAllControls = this.localStore.getBoolean(this.configKey());
+ }
+ }
+
+ public toggleShowAll() {
+ this.showAllControls = !this.showAllControls;
+
+ this.localStore.setBoolean(this.configKey(), this.showAllControls);
}
public ngDoCheck() {
@@ -70,5 +91,9 @@ export class ContentFieldComponent implements DoCheck, OnChanges {
this.selectedFormControl = control;
}
}
+
+ private configKey() {
+ return `squidex.schemas.${this.schema.id}.fields.${this.field.fieldId}.show-all`;
+ }
}
diff --git a/src/Squidex/app/features/content/pages/content/content-page.component.html b/src/Squidex/app/features/content/pages/content/content-page.component.html
index 452b1cfc7..a3f03d0c7 100644
--- a/src/Squidex/app/features/content/pages/content/content-page.component.html
+++ b/src/Squidex/app/features/content/pages/content/content-page.component.html
@@ -115,9 +115,10 @@
+ [fieldForm]="contentForm.form.get(field.name)"
+ [schema]="schema"
+ [languages]="languages"
+ [(language)]="language">
diff --git a/src/Squidex/app/features/content/shared/assets-editor.component.ts b/src/Squidex/app/features/content/shared/assets-editor.component.ts
index a675fbccc..49214df36 100644
--- a/src/Squidex/app/features/content/shared/assets-editor.component.ts
+++ b/src/Squidex/app/features/content/shared/assets-editor.component.ts
@@ -61,7 +61,7 @@ export class AssetsEditorComponent implements ControlValueAccessor, OnInit, OnDe
private readonly localStore: LocalStoreService,
private readonly messageBus: MessageBus
) {
- this.isListView = this.localStore.get('assetView') === 'List';
+ this.isListView = this.localStore.getBoolean('squidex.assets.list-view');
}
public writeValue(obj: any) {
@@ -171,9 +171,9 @@ export class AssetsEditorComponent implements ControlValueAccessor, OnInit, OnDe
}
public changeView(isListView: boolean) {
- this.localStore.set('assetView', isListView ? 'List' : 'Grid');
-
this.isListView = isListView;
+
+ this.localStore.setBoolean('squidex.assets.list-view', isListView);
}
private updateValue() {
diff --git a/src/Squidex/app/features/content/shared/field-editor.component.html b/src/Squidex/app/features/content/shared/field-editor.component.html
index 839cc3d84..5ff6aea85 100644
--- a/src/Squidex/app/features/content/shared/field-editor.component.html
+++ b/src/Squidex/app/features/content/shared/field-editor.component.html
@@ -1,6 +1,6 @@
Disabled
diff --git a/src/Squidex/app/features/content/shared/field-editor.component.ts b/src/Squidex/app/features/content/shared/field-editor.component.ts
index 4d441028c..e15497238 100644
--- a/src/Squidex/app/features/content/shared/field-editor.component.ts
+++ b/src/Squidex/app/features/content/shared/field-editor.component.ts
@@ -35,4 +35,7 @@ export class FieldEditorComponent {
@Input()
public languages: ImmutableArray;
+
+ @Input()
+ public displaySuffix: string;
}
\ No newline at end of file
diff --git a/src/Squidex/app/features/content/shared/preview-button.component.ts b/src/Squidex/app/features/content/shared/preview-button.component.ts
index 314642cc6..215500f7d 100644
--- a/src/Squidex/app/features/content/shared/preview-button.component.ts
+++ b/src/Squidex/app/features/content/shared/preview-button.component.ts
@@ -44,7 +44,7 @@ export class PreviewButtonComponent implements OnInit {
}
public ngOnInit() {
- let selectedName = this.localStore.get(`preview-button-${this.schema.id}`);
+ let selectedName = this.localStore.get(this.configKey());
if (!selectedName || !this.schema.previewUrls[selectedName]) {
selectedName = Object.keys(this.schema.previewUrls)[0];
@@ -69,6 +69,12 @@ export class PreviewButtonComponent implements OnInit {
this.alternativeNames = keys.filter(x => x !== this.selectedName);
this.alternativeNames.sort();
+
+ this.localStore.set(this.configKey(), selectedName);
}
}
+
+ private configKey() {
+ return `squidex.schemas.${this.schema.id}.preview-button`;
+ }
}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/angular/sorted.directive.ts b/src/Squidex/app/framework/angular/sorted.directive.ts
index 84d3fd47f..d70c00da2 100644
--- a/src/Squidex/app/framework/angular/sorted.directive.ts
+++ b/src/Squidex/app/framework/angular/sorted.directive.ts
@@ -7,13 +7,13 @@
import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
-import Sortable from 'sortablejs';
+import * as Sortable from 'sortablejs';
@Directive({
selector: '[sqxSortModel]'
})
export class SortedDirective implements OnDestroy, OnInit {
- private sortable: Sortable;
+ private sortable: Sortable.Ref;
@Input()
public dragHandle = '.drag-handle';
diff --git a/src/Squidex/app/framework/services/local-store.service.spec.ts b/src/Squidex/app/framework/services/local-store.service.spec.ts
index 765605c3b..20fa0d3a6 100644
--- a/src/Squidex/app/framework/services/local-store.service.spec.ts
+++ b/src/Squidex/app/framework/services/local-store.service.spec.ts
@@ -73,4 +73,16 @@ describe('LocalStore', () => {
expect(localStoreService.get('mykey')).toBe('myval');
});
+
+ it('should get boolean from local store', () => {
+ const localStoreService = new LocalStoreService();
+
+ localStoreService.setBoolean('key1', true);
+ localStoreService.setBoolean('key2', false);
+
+ expect(localStoreService.getBoolean('key1')).toBe(true);
+ expect(localStoreService.getBoolean('key2')).toBe(false);
+
+ expect(localStoreService.getBoolean('not_set')).toBe(false);
+ });
});
diff --git a/src/Squidex/app/framework/services/local-store.service.ts b/src/Squidex/app/framework/services/local-store.service.ts
index 364f7ac29..bcf718002 100644
--- a/src/Squidex/app/framework/services/local-store.service.ts
+++ b/src/Squidex/app/framework/services/local-store.service.ts
@@ -13,7 +13,7 @@ export const LocalStoreServiceFactory = () => {
@Injectable()
export class LocalStoreService {
- private readonly fallback = {};
+ private readonly fallback: { [key: string]: string } = {};
private store: any = localStorage;
public configureStore(store: any) {
@@ -28,6 +28,12 @@ export class LocalStoreService {
}
}
+ public getBoolean(key: string): boolean {
+ const value = this.get(key);
+
+ return value === 'true';
+ }
+
public set(key: string, value: string) {
try {
this.store.setItem(key, value);
@@ -35,4 +41,10 @@ export class LocalStoreService {
this.fallback[key] = value;
}
}
+
+ public setBoolean(key: string, value: boolean) {
+ const converted = value ? 'true' : 'false';
+
+ this.store.setItem(key, converted);
+ }
}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/services/onboarding.service.ts b/src/Squidex/app/framework/services/onboarding.service.ts
index 9a1144120..e2249d050 100644
--- a/src/Squidex/app/framework/services/onboarding.service.ts
+++ b/src/Squidex/app/framework/services/onboarding.service.ts
@@ -28,7 +28,7 @@ export class OnboardingService {
}
public disable(key: string) {
- this.localStore.set(`squidex.onboarding.disable.${key}`, '1');
+ this.localStore.set(this.getConfigKey(key), '1');
}
public shouldShow(key: string) {
@@ -36,6 +36,10 @@ export class OnboardingService {
}
private shouldShowKey(key: string) {
- return this.localStore.get(`squidex.onboarding.disable.${key}`) !== '1';
+ return this.localStore.get(this.getConfigKey(key)) !== '1';
+ }
+
+ private getConfigKey(key: string): string {
+ return `squidex.onboarding.disable.${key}`;
}
}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/assets-selector.component.ts b/src/Squidex/app/shared/components/assets-selector.component.ts
index 9dca033c3..ab9cbd615 100644
--- a/src/Squidex/app/shared/components/assets-selector.component.ts
+++ b/src/Squidex/app/shared/components/assets-selector.component.ts
@@ -39,7 +39,7 @@ export class AssetsSelectorComponent implements OnInit {
public readonly state: AssetsDialogState,
private readonly localStore: LocalStoreService
) {
- this.isListView = this.localStore.get('assetView') === 'List';
+ this.isListView = this.localStore.getBoolean('squidex.assets.list-view');
}
public ngOnInit() {
@@ -77,9 +77,9 @@ export class AssetsSelectorComponent implements OnInit {
}
public changeView(isListView: boolean) {
- this.localStore.set('assetView', isListView ? 'List' : 'Grid');
-
this.isListView = isListView;
+
+ this.localStore.setBoolean('squidex.assets.list-view', isListView);
}
}
diff --git a/src/Squidex/app/shared/components/language-selector.component.html b/src/Squidex/app/shared/components/language-selector.component.html
index f0f18e0ae..9e80798dc 100644
--- a/src/Squidex/app/shared/components/language-selector.component.html
+++ b/src/Squidex/app/shared/components/language-selector.component.html
@@ -10,7 +10,7 @@
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/language-selector.component.scss b/src/Squidex/app/shared/components/language-selector.component.scss
index eb7a3a1a8..10a1d636a 100644
--- a/src/Squidex/app/shared/components/language-selector.component.scss
+++ b/src/Squidex/app/shared/components/language-selector.component.scss
@@ -7,4 +7,7 @@
.iso-code {
font-family: monospace;
+ display: inline-block;
+ min-width: 40px;
+ max-width: 60px;
}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/schema-category.component.ts b/src/Squidex/app/shared/components/schema-category.component.ts
index f362d4a90..4b2901e44 100644
--- a/src/Squidex/app/shared/components/schema-category.component.ts
+++ b/src/Squidex/app/shared/components/schema-category.component.ts
@@ -64,13 +64,13 @@ export class SchemaCategoryComponent implements OnInit, OnChanges {
}
public ngOnInit() {
- this.isOpen = this.localStore.get(`schema-category.${this.name}`) !== 'false';
+ this.isOpen = !this.localStore.getBoolean(this.configKey());
}
public toggle() {
this.isOpen = !this.isOpen;
- this.localStore.set(`schema-category.${this.name}`, this.isOpen + '');
+ this.localStore.setBoolean(this.configKey(), !this.isOpen);
}
public ngOnChanges(changes: SimpleChanges): void {
@@ -115,4 +115,8 @@ export class SchemaCategoryComponent implements OnInit, OnChanges {
public trackBySchema(index: number, schema: SchemaDto) {
return schema.id;
}
+
+ private configKey(): string {
+ return `squidex.schema.category.${this.name}.closed`;
+ }
}
diff --git a/src/Squidex/app/shared/services/contents.service.ts b/src/Squidex/app/shared/services/contents.service.ts
index ae3579487..05bb55fd8 100644
--- a/src/Squidex/app/shared/services/contents.service.ts
+++ b/src/Squidex/app/shared/services/contents.service.ts
@@ -83,7 +83,7 @@ export class ContentsService {
if (query.indexOf('$filter') < 0 &&
query.indexOf('$search') < 0 &&
query.indexOf('$orderby') < 0) {
- queryParts.push(`$search="${query.trim()}"`);
+ queryParts.push(`$search="${encodeURIComponent(query.trim())}"`);
} else {
queryParts.push(`${query.trim()}`);
}
diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts
index 0bf1276dd..0ef69f5af 100644
--- a/src/Squidex/app/shared/services/schemas.service.ts
+++ b/src/Squidex/app/shared/services/schemas.service.ts
@@ -55,14 +55,14 @@ export class SchemaDetailsDto extends SchemaDto {
public listFieldsEditable: RootFieldDto[];
constructor(id: string, name: string, category: string,
- properties: SchemaPropertiesDto,
- isSingleton: boolean,
- isPublished: boolean,
- created: DateTime,
- createdBy: string,
- lastModified: DateTime,
- lastModifiedBy: string,
- version: Version,
+ properties: SchemaPropertiesDto,
+ isSingleton: boolean,
+ isPublished: boolean,
+ created: DateTime,
+ createdBy: string,
+ lastModified: DateTime,
+ lastModifiedBy: string,
+ version: Version,
public readonly fields: RootFieldDto[],
public readonly previewUrls: { [name: string]: string },
public readonly scriptQuery?: string,
diff --git a/src/Squidex/app/shared/services/schemas.types.ts b/src/Squidex/app/shared/services/schemas.types.ts
index 5e47756ba..9474aea8e 100644
--- a/src/Squidex/app/shared/services/schemas.types.ts
+++ b/src/Squidex/app/shared/services/schemas.types.ts
@@ -126,6 +126,10 @@ export abstract class FieldPropertiesDto {
}
}
+ public get isComplexUI() {
+ return true;
+ }
+
public abstract accept(visitor: FieldPropertiesVisitor): T;
}
@@ -179,6 +183,10 @@ export class BooleanFieldPropertiesDto extends FieldPropertiesDto {
public readonly inlineEditable: boolean = false;
public readonly defaultValue?: boolean;
+ public get isComplexUI() {
+ return false;
+ }
+
constructor(editor: string,
props?: Partial
) {
@@ -198,6 +206,10 @@ export class DateTimeFieldPropertiesDto extends FieldPropertiesDto {
public readonly minValue?: string;
public readonly calculatedDefaultValue?: string;
+ public get isComplexUI() {
+ return false;
+ }
+
constructor(editor: string,
props?: Partial
) {
@@ -247,6 +259,10 @@ export class NumberFieldPropertiesDto extends FieldPropertiesDto {
public readonly minValue?: number;
public readonly allowedValues?: number[];
+ public get isComplexUI() {
+ return false;
+ }
+
constructor(editor: string,
props?: Partial
) {
@@ -288,6 +304,10 @@ export class StringFieldPropertiesDto extends FieldPropertiesDto {
public readonly maxLength?: number;
public readonly allowedValues?: string[];
+ public get isComplexUI() {
+ return this.editor !== 'Input' && this.editor !== 'Color' && this.editor !== 'Radio' && this.editor !== 'Slug' && this.editor !== 'TextArea';
+ }
+
constructor(editor: string,
props?: Partial
) {
@@ -306,6 +326,10 @@ export class TagsFieldPropertiesDto extends FieldPropertiesDto {
public readonly maxItems?: number;
public readonly allowedValues?: string[];
+ public get isComplexUI() {
+ return false;
+ }
+
constructor(editor: string,
props?: Partial
) {
diff --git a/src/Squidex/package.json b/src/Squidex/package.json
index db6454054..cfa7ac929 100644
--- a/src/Squidex/package.json
+++ b/src/Squidex/package.json
@@ -73,7 +73,7 @@
"karma": "3.1.4",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "2.0.0",
- "karma-coverage-istanbul-reporter": "^2.0.4",
+ "karma-coverage-istanbul-reporter": "2.0.4",
"karma-htmlfile-reporter": "0.3.7",
"karma-jasmine": "2.0.1",
"karma-jasmine-html-reporter": "1.4.0",