mirror of https://github.com/Squidex/squidex.git
16 changed files with 335 additions and 100 deletions
@ -0,0 +1,70 @@ |
|||||
|
<sqx-modal-dialog (close)="complete()" large="true" fullHeight="true" contentClass="grid"> |
||||
|
<ng-container title> |
||||
|
Select contents |
||||
|
</ng-container> |
||||
|
|
||||
|
<ng-container tabs> |
||||
|
<form class="form-inline search-form" (ngSubmit)="search()"> |
||||
|
<input class="form-control form-control-expandable" [formControl]="contentsFilter" placeholder="Search for content" /> |
||||
|
|
||||
|
<a class="expand-search" (click)="searchModal.toggle()" #archive> |
||||
|
<i class="icon-caret-down"></i> |
||||
|
</a> |
||||
|
</form> |
||||
|
|
||||
|
<button class="btn btn-link btn-secondary" (click)="load(true)"> |
||||
|
<i class="icon-reset"></i> Refresh |
||||
|
</button> |
||||
|
</ng-container> |
||||
|
|
||||
|
<ng-container content> |
||||
|
<div class="grid-header"> |
||||
|
<table class="table table-items table-fixed" *ngIf="contentItems"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th class="cell-select"> |
||||
|
<input type="checkbox" class="form-control" [ngModel]="isAllSelected" (ngModelChange)="selectAll($event)" /> |
||||
|
</th> |
||||
|
<th class="cell-auto" *ngFor="let field of schemaFields"> |
||||
|
<span class="field">{{field.displayName}}</span> |
||||
|
</th> |
||||
|
<th class="cell-time"> |
||||
|
Updated |
||||
|
</th> |
||||
|
<th class="cell-user"> |
||||
|
By |
||||
|
</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
</table> |
||||
|
</div> |
||||
|
|
||||
|
<div class="grid-content"> |
||||
|
<div sqxIgnoreScrollbar> |
||||
|
<table class="table table-items table-fixed" *ngIf="contentItems"> |
||||
|
<tbody> |
||||
|
<ng-template ngFor let-content [ngForOf]="contentItems" [ngForTrackBy]="trackByContent"> |
||||
|
<tr [sqxContent]="content" |
||||
|
[selected]="isItemSelected(content)" |
||||
|
(selectedChange)="onContentSelected(content)" |
||||
|
[language]="languageSelected" |
||||
|
[schemaFields]="schemaFields" |
||||
|
[schema]="schema" |
||||
|
isReadOnly="true"></tr> |
||||
|
<tr class="spacer"></tr> |
||||
|
</ng-template> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="grid-footer"> |
||||
|
<sqx-pager [pager]="contentsPager"></sqx-pager> |
||||
|
</div> |
||||
|
</ng-container> |
||||
|
|
||||
|
<ng-container footer> |
||||
|
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button> |
||||
|
<button type="submit" class="float-right btn btn-success" (click)="select()" [disabled]="selectionCount === 0">Link selected contents ({{selectionCount}})</button> |
||||
|
</ng-container> |
||||
|
</sqx-modal-dialog> |
||||
@ -0,0 +1,38 @@ |
|||||
|
@import '_vars'; |
||||
|
@import '_mixins'; |
||||
|
|
||||
|
.content { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.icon-plus { |
||||
|
font-size: .8rem; |
||||
|
} |
||||
|
|
||||
|
.search-form { |
||||
|
display: inline-block; |
||||
|
} |
||||
|
|
||||
|
.form-inline { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.form-control-expandable { |
||||
|
padding-right: 1.5rem; |
||||
|
} |
||||
|
|
||||
|
.expand-search { |
||||
|
@include absolute(8px, 8px, auto, auto); |
||||
|
color: $color-border-dark !important; |
||||
|
font-size: .9rem; |
||||
|
font-weight: normal; |
||||
|
cursor: pointer !important; |
||||
|
} |
||||
|
|
||||
|
:host /deep/ .modal-body { |
||||
|
background: $color-background; |
||||
|
} |
||||
|
|
||||
|
:host /deep/ .modal-tabs { |
||||
|
background: $color-dark-foreground; |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; |
||||
|
import { FormControl } from '@angular/forms'; |
||||
|
|
||||
|
import { |
||||
|
AppsState, |
||||
|
ContentDto, |
||||
|
ContentsService, |
||||
|
DialogService, |
||||
|
FieldDto, |
||||
|
ImmutableArray, |
||||
|
ModalView, |
||||
|
Pager, |
||||
|
SchemaDetailsDto, |
||||
|
LanguageDto |
||||
|
} from '@app/shared'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-contents-selector', |
||||
|
styleUrls: ['./contents-selector.component.scss'], |
||||
|
templateUrl: './contents-selector.component.html' |
||||
|
}) |
||||
|
export class ContentsSelectorComponent implements OnInit { |
||||
|
@Input() |
||||
|
public language: LanguageDto[]; |
||||
|
|
||||
|
@Input() |
||||
|
public schema: SchemaDetailsDto; |
||||
|
|
||||
|
@Input() |
||||
|
public schemaFields: FieldDto[]; |
||||
|
|
||||
|
@Output() |
||||
|
public selected = new EventEmitter<ContentDto[]>(); |
||||
|
|
||||
|
public searchModal = new ModalView(); |
||||
|
|
||||
|
public contentItems: ImmutableArray<ContentDto>; |
||||
|
public contentsFilter = new FormControl(); |
||||
|
public contentsQuery = ''; |
||||
|
public contentsPager = new Pager(0); |
||||
|
|
||||
|
public selectedItems: { [id: string]: ContentDto; } = {}; |
||||
|
public selectionCount = 0; |
||||
|
|
||||
|
public isAllSelected = false; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly appsState: AppsState, |
||||
|
private readonly contentsService: ContentsService, |
||||
|
private readonly dialogs: DialogService |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public ngOnInit() { |
||||
|
this.load(); |
||||
|
} |
||||
|
|
||||
|
public load(showInfo = false) { |
||||
|
this.contentsService.getContents(this.appsState.appName, this.schema.name, this.contentsPager.pageSize, this.contentsPager.skip, this.contentsQuery, undefined, false) |
||||
|
.finally(() => { |
||||
|
this.selectedItems = {}; |
||||
|
|
||||
|
this.updateSelectionSummary(); |
||||
|
}) |
||||
|
.subscribe(dtos => { |
||||
|
this.contentItems = ImmutableArray.of(dtos.items); |
||||
|
this.contentsPager = this.contentsPager.setCount(dtos.total); |
||||
|
|
||||
|
if (showInfo) { |
||||
|
this.dialogs.notifyInfo('Contents reloaded.'); |
||||
|
} |
||||
|
}, error => { |
||||
|
this.dialogs.notifyError(error); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public search() { |
||||
|
this.contentsQuery = this.contentsFilter.value; |
||||
|
this.contentsPager = new Pager(0); |
||||
|
|
||||
|
this.load(); |
||||
|
} |
||||
|
|
||||
|
public goNext() { |
||||
|
this.contentsPager = this.contentsPager.goNext(); |
||||
|
|
||||
|
this.load(); |
||||
|
} |
||||
|
|
||||
|
public goPrev() { |
||||
|
this.contentsPager = this.contentsPager.goPrev(); |
||||
|
|
||||
|
this.load(); |
||||
|
} |
||||
|
|
||||
|
public isItemSelected(content: ContentDto) { |
||||
|
return this.selectedItems[content.id]; |
||||
|
} |
||||
|
|
||||
|
public complete() { |
||||
|
this.selected.emit([]); |
||||
|
} |
||||
|
|
||||
|
public select() { |
||||
|
this.selected.emit(Object.values(this.selectedItems)); |
||||
|
} |
||||
|
|
||||
|
public selectAll(isSelected: boolean) { |
||||
|
this.selectedItems = {}; |
||||
|
|
||||
|
if (isSelected) { |
||||
|
for (let content of this.contentItems.values) { |
||||
|
this.selectedItems[content.id] = content; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.updateSelectionSummary(); |
||||
|
} |
||||
|
|
||||
|
public onContentSelected(content: ContentDto) { |
||||
|
if (this.selectedItems[content.id]) { |
||||
|
delete this.selectedItems[content.id]; |
||||
|
} else { |
||||
|
this.selectedItems[content.id] = content; |
||||
|
} |
||||
|
|
||||
|
this.updateSelectionSummary(); |
||||
|
} |
||||
|
|
||||
|
private updateSelectionSummary() { |
||||
|
this.selectionCount = Object.keys(this.selectedItems).length; |
||||
|
|
||||
|
this.isAllSelected = this.selectionCount === this.contentItems.length; |
||||
|
} |
||||
|
|
||||
|
public trackByContent(content: ContentDto): string { |
||||
|
return content.id; |
||||
|
} |
||||
|
} |
||||
|
|
||||
Loading…
Reference in new issue