Browse Source

Collapse all items in array.

pull/425/head
Sebastian Stehle 7 years ago
parent
commit
3e96c21410
  1. 23
      src/Squidex/app/features/content/shared/array-editor.component.html
  2. 34
      src/Squidex/app/features/content/shared/array-editor.component.ts
  3. 74
      src/Squidex/app/features/content/shared/array-item.component.html
  4. 10
      src/Squidex/app/features/content/shared/array-item.component.scss
  5. 89
      src/Squidex/app/features/content/shared/array-item.component.ts

23
src/Squidex/app/features/content/shared/array-editor.component.html

@ -11,7 +11,6 @@
[form]="form"
[formContext]="formContext"
[field]="field"
[isHidden]="snapshot.isHidden"
[isDisabled]="arrayControl.disabled"
[isFirst]="i === 0"
[isLast]="i === arrayControl.controls.length - 1"
@ -21,16 +20,28 @@
[languages]="languages"
(clone)="itemAdd(itemForm)"
(move)="move(itemForm, $event)"
(remove)="itemRemove(i)"
(toggle)="hide($event)">
(remove)="itemRemove(i)">
<i cdkDragHandle class="icon-drag2"></i>
</sqx-array-item>
</div>
</div>
<button type="button" class="btn btn-success" [disabled]="field.nested.length === 0 || arrayControl.disabled" (click)="itemAdd(undefined)">
Add Item
</button>
<div class="row">
<div class="col">
<button type="button" class="btn btn-success" [disabled]="field.nested.length === 0 || arrayControl.disabled" (click)="itemAdd(undefined)">
Add Item
</button>
</div>
<div class="col-auto" *ngIf="arrayControl.controls.length > 0">
<button type="button" class="btn btn-text-secondary" (click)="expandAll()" title="Expand all items">
<i class="icon-plus-square"></i>
</button>
<button type="button" class="btn btn-text-secondary" (click)="collapseAll()" title="Collapse all items">
<i class="icon-minus-square"></i>
</button>
</div>
</div>
<small class="text-muted ml-2" *ngIf="field.nested.length === 0">
Add a nested field first to add items.

34
src/Squidex/app/features/content/shared/array-editor.component.ts

@ -6,20 +6,17 @@
*/
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, QueryList, ViewChildren } from '@angular/core';
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
import {
AppLanguageDto,
EditContentForm,
RootFieldDto,
sorted,
StatefulComponent
sorted
} from '@app/shared';
interface State {
isHidden: boolean;
}
import { ArrayItemComponent } from './array-item.component';
@Component({
selector: 'sqx-array-editor',
@ -27,7 +24,7 @@ interface State {
templateUrl: './array-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ArrayEditorComponent extends StatefulComponent<State> {
export class ArrayEditorComponent {
@Input()
public form: EditContentForm;
@ -46,15 +43,8 @@ export class ArrayEditorComponent extends StatefulComponent<State> {
@Input()
public arrayControl: FormArray;
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {
isHidden: false
});
}
public hide(isHidden: boolean) {
this.next(s => ({ ...s, isHidden }));
}
@ViewChildren(ArrayItemComponent)
public children: QueryList<ArrayItemComponent>;
public itemRemove(index: number) {
this.form.arrayItemRemove(this.field, this.language, index);
@ -68,6 +58,18 @@ export class ArrayEditorComponent extends StatefulComponent<State> {
this.sortInternal(sorted(event));
}
public collapseAll() {
this.children.forEach(component => {
component.collapse();
});
}
public expandAll() {
this.children.forEach(component => {
component.expand();
});
}
public move(control: AbstractControl, index: number) {
let controls = [...this.arrayControl.controls];

74
src/Squidex/app/features/content/shared/array-item.component.html

@ -1,41 +1,45 @@
<div class="card item" [class.invalid]="isInvalid | async">
<div class="card-header drag-handle">
<span class="pull-left">
<span class="mr-1">
<div class="row">
<div class="col-auto pr-1">
<ng-content></ng-content>
</span>
<span class="header-text text-decent">Item #{{index + 1}}</span>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isFirst" (click)="emitMoveTop()">
<i class="icon-caret-top"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isFirst" (click)="emitMoveUp()">
<i class="icon-caret-up"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isLast" (click)="emitMoveDown()">
<i class="icon-caret-down"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isLast" (click)="emitMoveBottom()">
<i class="icon-caret-bottom"></i>
</button>
<button type="button" class="btn btn-text-secondary" [class.hidden]="!isHidden" (click)="emitToggle(false)" title="Open all items">
<i class="icon-plus-square"></i>
</button>
<button type="button" class="btn btn-text-secondary" [class.hidden]="isHidden" (click)="emitToggle(true)" title="Close all items">
<i class="icon-minus-square"></i>
</button>
</span>
<span class="float-right">
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled" (click)="emitClone()">
<i class="icon-clone"></i>
</button>
<button type="button" class="btn btn-text-danger" [disabled]="isDisabled" (click)="emitRemove()">
<i class="icon-bin2"></i>
</button>
</span>
</div>
<div class="col">
<div class="truncate">
<span class="header-index">#{{index + 1}}</span>
<span class="header-title">{{title}}</span>
</div>
</div>
<div class="col-auto pr-4">
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isFirst" (click)="emitMoveTop()">
<i class="icon-caret-top"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isFirst" (click)="emitMoveUp()">
<i class="icon-caret-up"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isLast" (click)="emitMoveDown()">
<i class="icon-caret-down"></i>
</button>
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled || isLast" (click)="emitMoveBottom()">
<i class="icon-caret-bottom"></i>
</button>
<button type="button" class="btn btn-text-secondary" [class.hidden]="!isHidden" (click)="expand()" title="Expand this item">
<i class="icon-plus-square"></i>
</button>
<button type="button" class="btn btn-text-secondary" [class.hidden]="isHidden" (click)="collapse()" title="Collapse this item">
<i class="icon-minus-square"></i>
</button>
</div>
<div class="col-auto">
<button type="button" class="btn btn-text-secondary" [disabled]="isDisabled" (click)="emitClone()">
<i class="icon-clone"></i>
</button>
<button type="button" class="btn btn-text-danger" [disabled]="isDisabled" (click)="emitRemove()">
<i class="icon-bin2"></i>
</button>
</div>
</div>
</div>
<div class="card-body" [class.hidden]="isHidden">

10
src/Squidex/app/features/content/shared/array-item.component.scss

@ -19,13 +19,17 @@
line-height: 2.2rem;
}
.header-text {
.header-index {
display: inline-block;
min-width: 70px;
max-width: 100px;
min-width: 3rem;
max-width: 3rem;
}
}
.col {
overflow: hidden;
}
.btn-text-secondary {
padding: .375rem;
}

89
src/Squidex/app/features/content/shared/array-item.component.ts

@ -5,25 +5,31 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import { startWith } from 'rxjs/operators';
import {
AppLanguageDto,
EditContentForm,
FieldDto,
FieldFormatter,
invalid$,
RootFieldDto
} from '@app/shared';
type FieldControl = { field: FieldDto, control: AbstractControl };
@Component({
selector: 'sqx-array-item',
styleUrls: ['./array-item.component.scss'],
templateUrl: './array-item.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ArrayItemComponent implements OnChanges {
export class ArrayItemComponent implements OnChanges, OnDestroy {
private subscription: Subscription;
@Output()
public remove = new EventEmitter();
@ -33,9 +39,6 @@ export class ArrayItemComponent implements OnChanges {
@Output()
public clone = new EventEmitter();
@Output()
public toggle = new EventEmitter<boolean>();
@Input()
public form: EditContentForm;
@ -45,9 +48,6 @@ export class ArrayItemComponent implements OnChanges {
@Input()
public field: RootFieldDto;
@Input()
public isHidden = false;
@Input()
public isFirst = false;
@ -69,22 +69,85 @@ export class ArrayItemComponent implements OnChanges {
@Input()
public languages: ReadonlyArray<AppLanguageDto>;
public isHidden = false;
public isInvalid: Observable<boolean>;
public fieldControls: ReadonlyArray<{ field: FieldDto, control: AbstractControl }>;
public title: string;
public fieldControls: ReadonlyArray<FieldControl> = [];
constructor(
private readonly changeDetector: ChangeDetectorRef
) {
}
public ngOnDestroy() {
this.unsubscribeFromForm();
}
private unsubscribeFromForm() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
public ngOnChanges(changes: SimpleChanges) {
if (changes['itemForm']) {
this.isInvalid = invalid$(this.itemForm);
this.unsubscribeFromForm();
this.subscription =
this.itemForm.valueChanges.pipe(startWith(this.itemForm.value))
.subscribe(() => {
this.updateTitle();
});
}
if (changes['itemForm'] || changes['field']) {
this.fieldControls = this.field.nested.map(field => ({ field, control: this.itemForm.get(field.name)! })).filter(x => !x.field.properties.isContentField || !!x.control);
this.updateFields();
this.updateTitle();
}
}
public emitToggle(value: boolean) {
this.toggle.emit(value);
private updateFields() {
const fields: FieldControl[] = [];
for (let field of this.field.nested) {
const control = this.itemForm.get(field.name)!;
if (control || this.field.properties.isContentField) {
fields.push({ field, control });
}
}
this.fieldControls = fields;
}
private updateTitle() {
const values: string[] = [];
for (let { control, field } of this.fieldControls) {
const formatted = FieldFormatter.format(field, control.value);
if (formatted) {
values.push(formatted);
}
}
this.title = values.join(', ');
}
public collapse() {
this.isHidden = true;
this.changeDetector.detectChanges();
}
public expand() {
this.isHidden = false;
this.changeDetector.detectChanges();
}
public emitClone() {

Loading…
Cancel
Save