mirror of https://github.com/Squidex/squidex.git
Browse Source
* Field sections. * Just some minor things. * Final fixes for sections. * Another fix. * Build fix.pull/544/head
committed by
GitHub
25 changed files with 429 additions and 259 deletions
@ -0,0 +1,30 @@ |
|||
<div class="header" *ngIf="section.separator; let separator"> |
|||
<div class="row no-gutters"> |
|||
<div class="col-auto"> |
|||
<button type="button" class="btn btn-sm btn-text-secondary" (click)="toggle()"> |
|||
<i [class.icon-caret-right]="isCollapsed" [class.icon-caret-down]="!isCollapsed"></i> |
|||
</button> |
|||
</div> |
|||
<div class="col"> |
|||
<h3>{{separator!.displayName}}</h3> |
|||
|
|||
<sqx-form-hint *ngIf="separator!.properties.hints?.length > 0"> |
|||
{{separator!.properties.hints}} |
|||
</sqx-form-hint> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div [class.hidden]="isCollapsed"> |
|||
<sqx-content-field *ngFor="let field of section.fields; trackBy: trackByField" |
|||
[field]="field" |
|||
[fieldForm]="getFieldForm(field)" |
|||
[fieldFormCompare]="getFieldFormCompare(field)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schema]="schema"> |
|||
</sqx-content-field> |
|||
</div> |
|||
@ -0,0 +1,23 @@ |
|||
.btn { |
|||
& { |
|||
width: 2rem; |
|||
} |
|||
|
|||
&:focus { |
|||
border-color: transparent; |
|||
} |
|||
} |
|||
|
|||
h3 { |
|||
margin: 0; |
|||
} |
|||
|
|||
.header { |
|||
line-height: 2rem; |
|||
margin-bottom: .5rem; |
|||
margin-top: 1.5rem; |
|||
|
|||
h3 { |
|||
line-height: 2rem; |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; |
|||
import { AppLanguageDto, EditContentForm, LocalStoreService, RootFieldDto, SchemaDto } from '@app/shared'; |
|||
import { FieldSection } from './../../shared/group-fields.pipe'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-content-section', |
|||
styleUrls: ['./content-section.component.scss'], |
|||
templateUrl: './content-section.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class ContentSectionComponent implements OnChanges { |
|||
@Output() |
|||
public languageChange = new EventEmitter<AppLanguageDto>(); |
|||
|
|||
@Input() |
|||
public form: EditContentForm; |
|||
|
|||
@Input() |
|||
public formCompare?: EditContentForm; |
|||
|
|||
@Input() |
|||
public formContext: any; |
|||
|
|||
@Input() |
|||
public schema: SchemaDto; |
|||
|
|||
@Input() |
|||
public section: FieldSection<RootFieldDto>; |
|||
|
|||
@Input() |
|||
public language: AppLanguageDto; |
|||
|
|||
@Input() |
|||
public languages: ReadonlyArray<AppLanguageDto>; |
|||
|
|||
public isCollapsed: boolean; |
|||
|
|||
constructor( |
|||
private readonly localStore: LocalStoreService |
|||
) { |
|||
} |
|||
|
|||
public ngOnChanges() { |
|||
this.isCollapsed = this.localStore.getBoolean(this.configKey()); |
|||
} |
|||
|
|||
public toggle() { |
|||
this.isCollapsed = !this.isCollapsed; |
|||
|
|||
this.localStore.setBoolean(this.configKey(), this.isCollapsed); |
|||
} |
|||
|
|||
public getFieldForm(field: RootFieldDto) { |
|||
return this.form.form.get(field.name)!; |
|||
} |
|||
|
|||
public getFieldFormCompare(field: RootFieldDto) { |
|||
return this.formCompare?.form.get(field.name)!; |
|||
} |
|||
|
|||
public trackByField(index: number, field: RootFieldDto) { |
|||
return field.fieldId; |
|||
} |
|||
|
|||
private configKey(): string { |
|||
return `squidex.schemas.${this.schema?.id}.fields.${this.section?.separator?.fieldId}.closed`; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<div class="header" *ngIf="section.separator; let separator"> |
|||
<h3>{{separator!.displayName}}</h3> |
|||
|
|||
<sqx-form-hint *ngIf="separator!.properties.hints?.length > 0"> |
|||
{{separator!.properties.hints}} |
|||
</sqx-form-hint> |
|||
</div> |
|||
|
|||
<div class="form-group" *ngFor="let field of section.fields; trackBy: trackByField"> |
|||
<sqx-field-editor |
|||
[control]="getControl(field)" |
|||
[field]="field" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-field-editor> |
|||
</div> |
|||
@ -0,0 +1,9 @@ |
|||
.header { |
|||
line-height: 2rem; |
|||
margin-bottom: .5rem; |
|||
margin-top: 1.5rem; |
|||
|
|||
h3 { |
|||
line-height: 2rem; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { ChangeDetectionStrategy, Component, Input, QueryList, ViewChildren } from '@angular/core'; |
|||
import { FormGroup } from '@angular/forms'; |
|||
import { AppLanguageDto, EditContentForm, NestedFieldDto } from '@app/shared'; |
|||
import { FieldSection } from './../group-fields.pipe'; |
|||
import { FieldEditorComponent } from './field-editor.component'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-array-section', |
|||
styleUrls: ['./array-section.component.scss'], |
|||
templateUrl: './array-section.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class ArraySectionComponent { |
|||
@Input() |
|||
public itemForm: FormGroup; |
|||
|
|||
@Input() |
|||
public form: EditContentForm; |
|||
|
|||
@Input() |
|||
public formContext: any; |
|||
|
|||
@Input() |
|||
public language: AppLanguageDto; |
|||
|
|||
@Input() |
|||
public languages: ReadonlyArray<AppLanguageDto>; |
|||
|
|||
@Input() |
|||
public section: FieldSection<NestedFieldDto>; |
|||
|
|||
@ViewChildren(FieldEditorComponent) |
|||
public editors: QueryList<FieldEditorComponent>; |
|||
|
|||
public getControl(field: NestedFieldDto) { |
|||
return this.itemForm.get(field.name)!; |
|||
} |
|||
|
|||
public reset() { |
|||
this.editors.forEach(editor => { |
|||
editor.reset(); |
|||
}); |
|||
} |
|||
|
|||
public trackByField(index: number, field: NestedFieldDto) { |
|||
return field.fieldId; |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Pipe, PipeTransform } from '@angular/core'; |
|||
import { FieldDto } from '@app/shared'; |
|||
|
|||
export interface FieldSection<T> { |
|||
separator?: T; |
|||
|
|||
fields: ReadonlyArray<T>; |
|||
} |
|||
|
|||
@Pipe({ |
|||
name: 'sqxGroupFields', |
|||
pure: true |
|||
}) |
|||
export class GroupFieldsPipe<T extends FieldDto> implements PipeTransform { |
|||
public transform(fields: ReadonlyArray<T>) { |
|||
const sections: FieldSection<T>[] = []; |
|||
|
|||
let currentSeparator: T | undefined = undefined; |
|||
let currentFields: T[] = []; |
|||
|
|||
for (const field of fields) { |
|||
if (field.properties.isContentField) { |
|||
currentFields.push(field); |
|||
} else { |
|||
sections.push({ separator: currentSeparator, fields: currentFields }); |
|||
|
|||
currentFields = []; |
|||
currentSeparator = field; |
|||
} |
|||
} |
|||
|
|||
if (currentFields.length > 0) { |
|||
sections.push({ separator: currentSeparator, fields: currentFields }); |
|||
} |
|||
|
|||
return sections; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue