mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
partial selection model implementation
This commit is contained in:
@@ -30,9 +30,15 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
dateBefore: string
|
||||
|
||||
@Output()
|
||||
dateBeforeChange = new EventEmitter<string>()
|
||||
|
||||
@Input()
|
||||
dateAfter: string
|
||||
|
||||
@Output()
|
||||
dateAfterChange = new EventEmitter<string>()
|
||||
|
||||
@Input()
|
||||
title: string
|
||||
|
||||
@@ -83,6 +89,8 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.dateAfterChange.emit(this.dateAfter)
|
||||
this.dateBeforeChange.emit(this.dateBefore)
|
||||
this.datesSet.emit({after: this.dateAfter, before: this.dateBefore})
|
||||
}
|
||||
|
||||
@@ -91,12 +99,12 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
clearBefore() {
|
||||
this.dateBefore = null;
|
||||
this.dateBefore = null
|
||||
this.onChange()
|
||||
}
|
||||
|
||||
clearAfter() {
|
||||
this.dateAfter = null;
|
||||
this.dateAfter = null
|
||||
this.onChange()
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,14 @@
|
||||
<div class="btn-group" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
|
||||
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="type !== types.Editing && itemsSelected?.length > 0 ? 'btn-primary' : 'btn-outline-primary'">
|
||||
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="type !== types.Editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'">
|
||||
<div class="d-none d-md-inline">{{title}}</div>
|
||||
<div class="d-inline-block d-md-none">
|
||||
<svg class="toolbaricon" fill="currentColor">
|
||||
<use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
|
||||
</svg>
|
||||
</div>
|
||||
<ng-container *ngIf="type !== types.Editing && itemsSelected?.length > 0">
|
||||
<ng-container *ngIf="type !== types.Editing && selectionModel.selectionSize() > 0">
|
||||
<div class="badge bg-secondary text-light rounded-pill badge-corner">
|
||||
{{itemsSelected?.length}}
|
||||
{{selectionModel.selectionSize()}}
|
||||
</div>
|
||||
</ng-container>
|
||||
</button>
|
||||
@@ -19,9 +19,9 @@
|
||||
<input class="form-control" type="text" [(ngModel)]="filterText" placeholder="Filter {{title}}" (keyup.enter)="listFilterEnter()" #listFilterTextInput>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="toggleableItems" class="items">
|
||||
<ng-container *ngFor="let toggleableItem of toggleableItems | filter: filterText">
|
||||
<app-toggleable-dropdown-button [toggleableItem]="toggleableItem" (toggle)="toggleItem($event)"></app-toggleable-dropdown-button>
|
||||
<div *ngIf="selectionModel.items" class="items">
|
||||
<ng-container *ngFor="let toggleableItem of selectionModel.items | filter: filterText">
|
||||
<app-toggleable-dropdown-button [toggleableItem]="toggleableItem" (toggle)="selectionModel.toggle(toggleableItem.item)"></app-toggleable-dropdown-button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<button *ngIf="type == types.Editing" class="list-group-item list-group-item-action bg-light" (click)="dropdown.close()" [disabled]="!hasBeenToggled || (toggleableItems | filter: filterText).length == 0">
|
||||
|
@@ -3,12 +3,55 @@ import { FilterPipe } from 'src/app/pipes/filter.pipe';
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ToggleableItem, ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component';
|
||||
import { MatchingModel } from 'src/app/data/matching-model';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export enum FilterableDropdownType {
|
||||
Filtering = 'filtering',
|
||||
Editing = 'editing'
|
||||
}
|
||||
|
||||
export class FilterableDropdownSelectionModel {
|
||||
|
||||
changed = new Subject<FilterableDropdownSelectionModel>()
|
||||
|
||||
multiple = false
|
||||
|
||||
items: ToggleableItem[] = []
|
||||
|
||||
getSelected() {
|
||||
return this.items.filter(i => i.state == ToggleableItemState.Selected).map(i => i.item)
|
||||
}
|
||||
|
||||
|
||||
|
||||
toggle(item: MatchingModel, fireEvent = true) {
|
||||
console.log("TOGGLE TAG")
|
||||
let toggleableItem = this.items.find(i => i.item == item)
|
||||
console.log(toggleableItem)
|
||||
|
||||
if (toggleableItem) {
|
||||
if (toggleableItem.state == ToggleableItemState.Selected) {
|
||||
toggleableItem.state = ToggleableItemState.NotSelected
|
||||
} else {
|
||||
this.items.forEach(i => {
|
||||
if (i.item == item) {
|
||||
i.state = ToggleableItemState.Selected
|
||||
} else if (!this.multiple) {
|
||||
i.state = ToggleableItemState.NotSelected
|
||||
}
|
||||
})
|
||||
}
|
||||
if (fireEvent) {
|
||||
this.changed.next(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectionSize() {
|
||||
return this.getSelected().length
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-filterable-dropdown',
|
||||
templateUrl: './filterable-dropdown.component.html',
|
||||
@@ -24,33 +67,45 @@ export class FilterableDropdownComponent {
|
||||
@Input()
|
||||
set items(items: MatchingModel[]) {
|
||||
if (items) {
|
||||
this._toggleableItems = items.map(i => {
|
||||
this._selectionModel.items = items.map(i => {
|
||||
return {item: i, state: ToggleableItemState.NotSelected, count: i.document_count}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_toggleableItems: ToggleableItem[] = []
|
||||
|
||||
@Input()
|
||||
set toggleableItems (toggleableItems: ToggleableItem[]) {
|
||||
if (this.type == FilterableDropdownType.Editing && this.dropdown?.isOpen()) return
|
||||
else this._toggleableItems = toggleableItems
|
||||
get items(): MatchingModel[] {
|
||||
return this._selectionModel.items.map(i => i.item)
|
||||
}
|
||||
|
||||
get toggleableItems(): ToggleableItem[] {
|
||||
return this._toggleableItems
|
||||
}
|
||||
_selectionModel = new FilterableDropdownSelectionModel()
|
||||
|
||||
@Input()
|
||||
set itemsSelected(itemsSelected: MatchingModel[]) {
|
||||
this.toggleableItems.forEach(i => {
|
||||
i.state = (itemsSelected.find(is => is.id == i.item.id)) ? ToggleableItemState.Selected : ToggleableItemState.NotSelected
|
||||
set selectionModel(model: FilterableDropdownSelectionModel) {
|
||||
if (this.selectionModel) {
|
||||
this.selectionModel.changed.complete()
|
||||
model.items = this.selectionModel.items
|
||||
model.multiple = this.selectionModel.multiple
|
||||
}
|
||||
model.changed.subscribe(updatedModel => {
|
||||
this.selectionModelChange.next(updatedModel)
|
||||
})
|
||||
this._selectionModel = model
|
||||
}
|
||||
|
||||
get itemsSelected(): MatchingModel[] {
|
||||
return this.toggleableItems.filter(ti => ti.state == ToggleableItemState.Selected).map(ti => ti.item)
|
||||
get selectionModel(): FilterableDropdownSelectionModel {
|
||||
return this._selectionModel
|
||||
}
|
||||
|
||||
@Output()
|
||||
selectionModelChange = new EventEmitter<FilterableDropdownSelectionModel>()
|
||||
|
||||
@Input()
|
||||
set multiple(value: boolean) {
|
||||
this.selectionModel.multiple = value
|
||||
}
|
||||
|
||||
get multiple() {
|
||||
return this.selectionModel.multiple
|
||||
}
|
||||
|
||||
@Input()
|
||||
@@ -64,50 +119,40 @@ export class FilterableDropdownComponent {
|
||||
|
||||
types = FilterableDropdownType
|
||||
|
||||
@Input()
|
||||
singular: boolean = false
|
||||
|
||||
@Output()
|
||||
toggle = new EventEmitter()
|
||||
|
||||
@Output()
|
||||
open = new EventEmitter()
|
||||
|
||||
@Output()
|
||||
editingComplete = new EventEmitter()
|
||||
|
||||
hasBeenToggled:boolean = false
|
||||
|
||||
constructor(private filterPipe: FilterPipe) { }
|
||||
constructor(private filterPipe: FilterPipe) {
|
||||
this.selectionModel = new FilterableDropdownSelectionModel()
|
||||
}
|
||||
|
||||
toggleItem(toggleableItem: ToggleableItem): void {
|
||||
if (this.singular && toggleableItem.state == ToggleableItemState.Selected) {
|
||||
this._toggleableItems.filter(ti => ti.item.id !== toggleableItem.item.id).forEach(ti => ti.state = ToggleableItemState.NotSelected)
|
||||
}
|
||||
this.hasBeenToggled = true
|
||||
this.toggle.emit(toggleableItem.item)
|
||||
// if (this.singular && toggleableItem.state == ToggleableItemState.Selected) {
|
||||
// this.selectionModel.items.filter(ti => ti.item.id !== toggleableItem.item.id).forEach(ti => ti.state = ToggleableItemState.NotSelected)
|
||||
// }
|
||||
// this.hasBeenToggled = true
|
||||
// this.toggle.emit(toggleableItem.item)
|
||||
}
|
||||
|
||||
dropdownOpenChange(open: boolean): void {
|
||||
if (open) {
|
||||
setTimeout(() => {
|
||||
this.listFilterTextInput.nativeElement.focus();
|
||||
}, 0)
|
||||
this.hasBeenToggled = false
|
||||
this.open.next()
|
||||
} else {
|
||||
this.filterText = ''
|
||||
if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.toggleableItems)
|
||||
}
|
||||
// if (open) {
|
||||
// setTimeout(() => {
|
||||
// this.listFilterTextInput.nativeElement.focus();
|
||||
// }, 0)
|
||||
// this.hasBeenToggled = false
|
||||
// this.open.next()
|
||||
// } else {
|
||||
// this.filterText = ''
|
||||
// if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.toggleableItems)
|
||||
// }
|
||||
}
|
||||
|
||||
listFilterEnter(): void {
|
||||
let filtered = this.filterPipe.transform(this.toggleableItems, this.filterText)
|
||||
if (filtered.length == 1) {
|
||||
let toggleableItem = this.toggleableItems.find(ti => ti.item.id == filtered[0].item.id)
|
||||
if (toggleableItem) toggleableItem.state = ToggleableItemState.Selected
|
||||
this.toggleItem(filtered[0])
|
||||
this.dropdown.close()
|
||||
}
|
||||
// let filtered = this.filterPipe.transform(this.toggleableItems, this.filterText)
|
||||
// if (filtered.length == 1) {
|
||||
// let toggleableItem = this.toggleableItems.find(ti => ti.item.id == filtered[0].item.id)
|
||||
// if (toggleableItem) toggleableItem.state = ToggleableItemState.Selected
|
||||
// this.toggleItem(filtered[0])
|
||||
// this.dropdown.close()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@@ -31,8 +31,7 @@ export class ToggleableDropdownButtonComponent {
|
||||
}
|
||||
|
||||
toggleItem(): void {
|
||||
this.toggleableItem.state = (this.toggleableItem.state == ToggleableItemState.NotSelected || this.toggleableItem.state == ToggleableItemState.PartiallySelected) ? ToggleableItemState.Selected : ToggleableItemState.NotSelected
|
||||
this.toggle.emit(this.toggleableItem)
|
||||
this.toggle.emit()
|
||||
}
|
||||
|
||||
getSelectedIconName() {
|
||||
|
Reference in New Issue
Block a user