Separates the attachment field to a custom component
- Refactores also the 'search-value-selector.component'
This commit is contained in:
parent
46f39f96e8
commit
dfa80e9cd0
@ -21,7 +21,6 @@
|
||||
<div *ngIf="itemObserver.value.length > 0">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="form"
|
||||
[formControl]="form.get('agenda_parent_id')"
|
||||
[multiple]="false"
|
||||
[includeNone]="true"
|
||||
|
@ -0,0 +1,29 @@
|
||||
<div class="attachment-container" *ngIf="controlName">
|
||||
<os-search-value-selector
|
||||
class="selector"
|
||||
ngDefaultControl
|
||||
[multiple]="true"
|
||||
listname="{{ 'Attachments' | translate }}"
|
||||
[formControl]="controlName"
|
||||
[InputListValues]="mediaFileList"
|
||||
></os-search-value-selector>
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="openUploadDialog(uploadDialog)"
|
||||
*osPerms="'mediafiles.can_upload'"
|
||||
>
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- upload file dialog -->
|
||||
<ng-template #uploadDialog>
|
||||
<h1 mat-dialog-title>
|
||||
<span translate>Upload files</span>
|
||||
</h1>
|
||||
<os-media-upload-content
|
||||
(uploadSuccessEvent)="uploadSuccess($event)"
|
||||
(errorEvent)="uploadError($event)"
|
||||
></os-media-upload-content>
|
||||
</ng-template>
|
@ -0,0 +1,14 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
|
||||
.attachment-container {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
.selector {
|
||||
width: 95%;
|
||||
}
|
||||
.mat-icon-button {
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
|
||||
import { AttachmentControlComponent } from './attachment-control.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('AttachmentControlComponent', () => {
|
||||
let component: AttachmentControlComponent;
|
||||
let fixture: ComponentFixture<AttachmentControlComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AttachmentControlComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,107 @@
|
||||
import { Component, OnInit, TemplateRef, Output, EventEmitter, Input } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { FormControl, ControlValueAccessor } from '@angular/forms';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||
|
||||
@Component({
|
||||
selector: 'os-attachment-control',
|
||||
templateUrl: './attachment-control.component.html',
|
||||
styleUrls: ['./attachment-control.component.scss']
|
||||
})
|
||||
export class AttachmentControlComponent implements OnInit, ControlValueAccessor {
|
||||
/**
|
||||
* Output for an error handler
|
||||
*/
|
||||
@Output()
|
||||
public errorHandler: EventEmitter<string> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* The form-control name to access the value for the form-control
|
||||
*/
|
||||
@Input()
|
||||
public controlName: FormControl;
|
||||
|
||||
/**
|
||||
* The file list that is necessary for the `SearchValueSelector`
|
||||
*/
|
||||
public mediaFileList: BehaviorSubject<ViewMediafile[]> = new BehaviorSubject([]);
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param dialogService Reference to the `MatDialog`
|
||||
* @param mediaService Reference for the `MediaFileRepositoryService`
|
||||
*/
|
||||
public constructor(private dialogService: MatDialog, private mediaService: MediafileRepositoryService) {}
|
||||
|
||||
/**
|
||||
* On init method
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.mediaFileList = this.mediaService.getViewModelListBehaviorSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to open a given dialog
|
||||
*
|
||||
* @param dialog the dialog to open
|
||||
*/
|
||||
public openUploadDialog(dialog: TemplateRef<string>): void {
|
||||
this.dialogService.open(dialog, {
|
||||
width: '750px',
|
||||
maxWidth: '90vw',
|
||||
maxHeight: '90vh'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to set the value for the `SearchValueSelector` after successful upload
|
||||
*
|
||||
* @param fileIDs a list with the ids of the uploaded files
|
||||
*/
|
||||
public uploadSuccess(fileIDs: number[]): void {
|
||||
if (this.controlName) {
|
||||
const newValues = [...this.controlName.value, ...fileIDs];
|
||||
this.controlName.setValue(newValues);
|
||||
this.dialogService.closeAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to emit an occurring error.
|
||||
*
|
||||
* @param error The occurring error
|
||||
*/
|
||||
public uploadError(error: string): void {
|
||||
this.errorHandler.emit(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to write a new value to the form.
|
||||
* Satisfy the interface.
|
||||
*
|
||||
* @param value The new value for this form.
|
||||
*/
|
||||
public writeValue(value: any): void {
|
||||
if (value && this.controlName) {
|
||||
this.controlName.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function executed when the control's value changed.
|
||||
*
|
||||
* @param fn the function that is executed.
|
||||
*/
|
||||
public registerOnChange(fn: any): void {}
|
||||
|
||||
/**
|
||||
* To satisfy the interface
|
||||
*
|
||||
* @param fn the registered callback function for onBlur-events.
|
||||
*/
|
||||
public registerOnTouched(fn: any): void {}
|
||||
}
|
@ -36,10 +36,8 @@
|
||||
<os-search-value-selector
|
||||
*ngIf="searchList"
|
||||
ngDefaultControl
|
||||
[form]="extensionFieldForm"
|
||||
[formControl]="extensionFieldForm.get('list')"
|
||||
[fullWidth]="true"
|
||||
[multiple]="false"
|
||||
[InputListValues]="searchList"
|
||||
[listname]="searchListLabel"
|
||||
></os-search-value-selector>
|
||||
|
@ -1,25 +1,14 @@
|
||||
<mat-form-field [formGroup]="form" [style.display]="fullWidth ? 'block' : 'inline-block'">
|
||||
<mat-form-field [style.display]="fullWidth ? 'block' : 'inline-block'">
|
||||
<mat-select [formControl]="formControl" placeholder="{{ listname | translate }}" [multiple]="multiple" #thisSelector>
|
||||
<ngx-mat-select-search [formControl]="filterControl"></ngx-mat-select-search>
|
||||
<ngx-mat-select-search ngModel (ngModelChange)="onSearch($event)"></ngx-mat-select-search>
|
||||
<div *ngIf="!multiple && includeNone">
|
||||
<mat-option [value]="null">
|
||||
<span>–</span>
|
||||
</mat-option>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<mat-option *ngFor="let selectedItem of filteredItems | async" [value]="selectedItem.id">
|
||||
<mat-option *ngFor="let selectedItem of getFilteredItems()" [value]="selectedItem.id">
|
||||
{{ selectedItem.getTitle() | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<div *ngIf="dispSelected">
|
||||
<p>
|
||||
<span translate>Selected values</span>:
|
||||
</p>
|
||||
<mat-chip-list #chipList>
|
||||
<mat-chip *ngFor="let selectedItem of thisSelector?.value" (removed)="remove(selectedItem)">
|
||||
{{ selectedItem.name }}
|
||||
<mat-icon (click)="remove(selectedItem)">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
|
@ -45,7 +45,6 @@ describe('SearchValueSelectorComponent', () => {
|
||||
const formGroup = formBuilder.group({
|
||||
testArray: []
|
||||
});
|
||||
hostComponent.searchValueSelectorComponent.form = formGroup;
|
||||
hostComponent.searchValueSelectorComponent.formControl = <FormControl>formGroup.get('testArray');
|
||||
|
||||
hostFixture.detectChanges();
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Component, OnInit, Input, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { Component, Input, ViewChild, OnDestroy } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatSelect } from '@angular/material';
|
||||
|
||||
import { Subject, ReplaySubject, BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { auditTime } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Selectable } from '../selectable';
|
||||
@ -25,7 +25,6 @@ import { Selectable } from '../selectable';
|
||||
* [multiple]="true"
|
||||
* placeholder="Placeholder"
|
||||
* [InputListValues]="myListValues"
|
||||
* [form]="myform_name"
|
||||
* [formControl]="myformcontrol">
|
||||
* </os-search-value-selector>
|
||||
* ```
|
||||
@ -37,38 +36,27 @@ import { Selectable } from '../selectable';
|
||||
templateUrl: './search-value-selector.component.html',
|
||||
styleUrls: ['./search-value-selector.component.scss']
|
||||
})
|
||||
export class SearchValueSelectorComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* ngModel variable - Deprecated with Angular 7
|
||||
* DO NOT USE: READ AT remove() FUNCTION!
|
||||
*/
|
||||
public myModel = [];
|
||||
|
||||
/**
|
||||
* Control for the filtering of the list
|
||||
*/
|
||||
public filterControl = new FormControl();
|
||||
|
||||
/**
|
||||
* List of the filtered content, when entering something in the search bar
|
||||
*/
|
||||
public filteredItems: ReplaySubject<Selectable[]> = new ReplaySubject<Selectable[]>(1);
|
||||
|
||||
/**
|
||||
* The inputlist subject.
|
||||
*/
|
||||
private _inputListSubject: BehaviorSubject<Selectable[]>;
|
||||
|
||||
export class SearchValueSelectorComponent implements OnDestroy {
|
||||
/**
|
||||
* Saves the current subscription to _inputListSubject.
|
||||
*/
|
||||
private _inputListSubscription: Subscription = null;
|
||||
|
||||
/**
|
||||
* Value of the search input
|
||||
*/
|
||||
private searchValue = '';
|
||||
|
||||
/**
|
||||
* All items
|
||||
*/
|
||||
private selectableItems: Selectable[];
|
||||
|
||||
/**
|
||||
* Decide if this should be a single or multi-select-field
|
||||
*/
|
||||
@Input()
|
||||
public multiple: boolean;
|
||||
public multiple = false;
|
||||
|
||||
/**
|
||||
* Decide, if none should be included, if multiple is false.
|
||||
@ -95,9 +83,14 @@ export class SearchValueSelectorComponent implements OnInit, OnDestroy {
|
||||
if (this._inputListSubscription) {
|
||||
this._inputListSubscription.unsubscribe();
|
||||
}
|
||||
this._inputListSubject = value;
|
||||
this._inputListSubscription = this._inputListSubject.subscribe(() => {
|
||||
this.filterItems();
|
||||
// this.inputSubject = value;
|
||||
this._inputListSubscription = value.pipe(auditTime(10)).subscribe(items => {
|
||||
this.selectableItems = items;
|
||||
if (this.formControl) {
|
||||
items.length === 0
|
||||
? this.formControl.disable({ emitEvent: false })
|
||||
: this.formControl.enable({ emitEvent: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,56 +100,23 @@ export class SearchValueSelectorComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
public listname: String;
|
||||
|
||||
/**
|
||||
* Form Group
|
||||
*/
|
||||
@Input()
|
||||
public form: FormGroup;
|
||||
|
||||
/**
|
||||
* Name of the Form
|
||||
*/
|
||||
@Input()
|
||||
public formControl: FormControl;
|
||||
|
||||
/**
|
||||
* DO NOT USE UNTIL BUG IN UPSTREAM ARE RESOLVED!
|
||||
* READ AT FUNCTION remove()
|
||||
*
|
||||
* Displayes the selected Items as Chip-List
|
||||
*/
|
||||
// @Input()
|
||||
public dispSelected = false;
|
||||
|
||||
/**
|
||||
* The MultiSelect Component
|
||||
*/
|
||||
@ViewChild('thisSelector', { static: true })
|
||||
public thisSelector: MatSelect;
|
||||
|
||||
/**
|
||||
* Subject that emits when the component has been destroyed
|
||||
*/
|
||||
private _onDestroy = new Subject<void>();
|
||||
|
||||
/**
|
||||
* Empty constructor
|
||||
*/
|
||||
public constructor(protected translate: TranslateService) {}
|
||||
|
||||
/**
|
||||
* onInit with filter ans subscription on filter
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
if (this._inputListSubject) {
|
||||
this.filteredItems.next(this._inputListSubject.getValue());
|
||||
}
|
||||
// listen to value changes
|
||||
this.filterControl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
||||
this.filterItems();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe on destroing.
|
||||
*/
|
||||
@ -164,53 +124,31 @@ export class SearchValueSelectorComponent implements OnInit, OnDestroy {
|
||||
if (this._inputListSubscription) {
|
||||
this._inputListSubscription.unsubscribe();
|
||||
}
|
||||
this._onDestroy.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* the filter function itself
|
||||
* Function to get a list filtered by the entered search value.
|
||||
*
|
||||
* @returns The filtered list of items.
|
||||
*/
|
||||
private filterItems(): void {
|
||||
if (!this._inputListSubject) {
|
||||
return;
|
||||
}
|
||||
// get the search keyword
|
||||
let search = this.filterControl.value;
|
||||
if (!search) {
|
||||
this.filteredItems.next(this._inputListSubject.getValue());
|
||||
return;
|
||||
} else {
|
||||
search = search.toLowerCase();
|
||||
}
|
||||
// filter the values
|
||||
this.filteredItems.next(
|
||||
this._inputListSubject.getValue().filter(
|
||||
selectedItem =>
|
||||
selectedItem
|
||||
public getFilteredItems(): Selectable[] {
|
||||
if (this.selectableItems) {
|
||||
return this.selectableItems.filter(
|
||||
item =>
|
||||
item
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.indexOf(search) > -1
|
||||
)
|
||||
);
|
||||
.indexOf(this.searchValue) > -1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the dispSelected value is marked as true, a chipList should be shown below the
|
||||
* selection list. Unfortunately it is not possible (yet) to change the datamodel in the backend
|
||||
* https://github.com/angular/material2/issues/10085 - therefore you can display the values in two
|
||||
* places, but can't reflect the changes in both places. Until this can be done this will be unused code
|
||||
* @param item the selected item to be removed
|
||||
* Function to set the search value.
|
||||
*
|
||||
* @param searchValue the new value the user is searching for.
|
||||
*/
|
||||
public remove(item: Selectable): void {
|
||||
const myArr = this.thisSelector.value;
|
||||
const index = myArr.indexOf(item, 0);
|
||||
// my model was the form according to fix
|
||||
// https://github.com/angular/material2/issues/10044
|
||||
// but this causes bad behaviour and will be depricated in Angular 7
|
||||
this.myModel = this.myModel.slice(index, 1);
|
||||
if (index > -1) {
|
||||
myArr.splice(index, 1);
|
||||
}
|
||||
this.thisSelector.value = myArr;
|
||||
public onSearch(searchValue: string): void {
|
||||
this.searchValue = searchValue.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ import { IconContainerComponent } from './components/icon-container/icon-contain
|
||||
import { ListViewTableComponent } from './components/list-view-table/list-view-table.component';
|
||||
import { AgendaContentObjectFormComponent } from './components/agenda-content-object-form/agenda-content-object-form.component';
|
||||
import { ExtensionFieldComponent } from './components/extension-field/extension-field.component';
|
||||
import { AttachmentControlComponent } from './components/attachment-control/attachment-control.component';
|
||||
|
||||
/**
|
||||
* Share Module for all "dumb" components and pipes.
|
||||
@ -214,6 +215,7 @@ import { ExtensionFieldComponent } from './components/extension-field/extension-
|
||||
SlideContainerComponent,
|
||||
CountdownTimeComponent,
|
||||
MediaUploadContentComponent,
|
||||
AttachmentControlComponent,
|
||||
PrecisionPipe,
|
||||
SpeakerButtonComponent,
|
||||
GridLayoutComponent,
|
||||
@ -262,7 +264,8 @@ import { ExtensionFieldComponent } from './components/extension-field/extension-
|
||||
IconContainerComponent,
|
||||
ListViewTableComponent,
|
||||
AgendaContentObjectFormComponent,
|
||||
ExtensionFieldComponent
|
||||
ExtensionFieldComponent,
|
||||
AttachmentControlComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: DateAdapter, useClass: OpenSlidesDateAdapter },
|
||||
|
@ -121,9 +121,7 @@
|
||||
<os-search-value-selector
|
||||
class="search-users"
|
||||
ngDefaultControl
|
||||
[form]="addSpeakerForm"
|
||||
[formControl]="addSpeakerForm.get('user_id')"
|
||||
[multiple]="false"
|
||||
listname="{{ 'Select or search new speaker ...' | translate }}"
|
||||
[InputListValues]="filteredUsers"
|
||||
></os-search-value-selector>
|
||||
|
@ -195,7 +195,6 @@
|
||||
<os-search-value-selector
|
||||
class="search-bar"
|
||||
ngDefaultControl
|
||||
[form]="candidatesForm"
|
||||
[formControl]="candidatesForm.get('userId')"
|
||||
[multiple]="false"
|
||||
listname="{{ 'Select a new candidate' | translate }}"
|
||||
@ -259,7 +258,6 @@
|
||||
<div class="content-field" *ngIf="tagsAvailable">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="assignmentForm"
|
||||
[formControl]="assignmentForm.get('tags_id')"
|
||||
[multiple]="true"
|
||||
[includeNone]="true"
|
||||
@ -269,15 +267,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Attachments -->
|
||||
<div class="content-field" *ngIf="mediafilesAvailable">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="assignmentForm"
|
||||
[formControl]="assignmentForm.get('attachments_id')"
|
||||
[multiple]="true"
|
||||
listname="{{ 'Election documents' | translate }}"
|
||||
[InputListValues]="mediafilesObserver"
|
||||
></os-search-value-selector>
|
||||
<div class="content-field">
|
||||
<os-attachment-control (errorHandler)="raiseError($event)" [controlName]="assignmentForm.get('attachments_id')"></os-attachment-control>
|
||||
</div>
|
||||
|
||||
<os-agenda-content-object-form *ngIf="newAssignment" [form]="assignmentForm"></os-agenda-content-object-form>
|
||||
|
@ -16,7 +16,6 @@
|
||||
<span>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="modelSelectForm"
|
||||
[formControl]="modelSelectForm.get('model')"
|
||||
[multiple]="false"
|
||||
[includeNone]="false"
|
||||
|
@ -21,7 +21,6 @@
|
||||
<p>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="createForm"
|
||||
[formControl]="this.createForm.get('read_groups_id')"
|
||||
[multiple]="true"
|
||||
listname="Groups with read permissions"
|
||||
@ -31,7 +30,6 @@
|
||||
<p>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="createForm"
|
||||
[formControl]="this.createForm.get('write_groups_id')"
|
||||
[multiple]="true"
|
||||
listname="Groups with write permissions"
|
||||
@ -93,7 +91,6 @@
|
||||
<p>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="updateForm"
|
||||
[formControl]="this.updateForm.get('read_groups_id')"
|
||||
[multiple]="true"
|
||||
listname="Groups with read permissions"
|
||||
@ -103,7 +100,6 @@
|
||||
<p>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="updateForm"
|
||||
[formControl]="this.updateForm.get('write_groups_id')"
|
||||
[multiple]="true"
|
||||
listname="Groups with write permissions"
|
||||
|
@ -37,9 +37,7 @@
|
||||
<os-search-value-selector
|
||||
class="search-users"
|
||||
ngDefaultControl
|
||||
[form]="addSubmitterForm"
|
||||
[formControl]="addSubmitterForm.get('userId')"
|
||||
[multiple]="false"
|
||||
listname="{{ 'Select or search new submitter ...' | translate }}"
|
||||
[InputListValues]="users"
|
||||
></os-search-value-selector>
|
||||
|
@ -581,7 +581,6 @@
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
[formControl]="contentForm.get('submitters_id')"
|
||||
[multiple]="true"
|
||||
listname="{{ 'Submitters' | translate }}"
|
||||
@ -763,9 +762,7 @@
|
||||
<div class="content-field" *ngIf="newMotion && categoryObserver.value.length > 0">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
[formControl]="contentForm.get('category_id')"
|
||||
[multiple]="false"
|
||||
[includeNone]="true"
|
||||
listname="{{ 'Category' | translate }}"
|
||||
[InputListValues]="categoryObserver"
|
||||
@ -783,24 +780,8 @@
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
<div *osPerms="'motions.can_manage'; and: editMotion" class="shortened-selector">
|
||||
<os-search-value-selector
|
||||
class="selector"
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
[formControl]="contentForm.get('attachments_id')"
|
||||
[multiple]="true"
|
||||
listname="{{ 'Attachments' | translate }}"
|
||||
[InputListValues]="mediafilesObserver"
|
||||
></os-search-value-selector>
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="onUploadAttachmentsButton(uploadDialog)"
|
||||
*osPerms="'mediafiles.can_upload'"
|
||||
>
|
||||
<mat-icon>cloud_upload</mat-icon>
|
||||
</button>
|
||||
<div *osPerms="'motions.can_manage'; and: editMotion">
|
||||
<os-attachment-control (errorHandler)="showUploadError($event)" [controlName]="contentForm.get('attachments_id')"></os-attachment-control>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -813,7 +794,6 @@
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
[formControl]="contentForm.get('supporters_id')"
|
||||
[multiple]="true"
|
||||
listname="{{ 'Supporters' | translate }}"
|
||||
@ -827,9 +807,7 @@
|
||||
<div *ngIf="perms.isAllowed('change_metadata', motion)">
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="contentForm"
|
||||
[formControl]="contentForm.get('workflow_id')"
|
||||
[multiple]="false"
|
||||
listname="{{ 'Workflow' | translate }}"
|
||||
[InputListValues]="workflowObserver"
|
||||
></os-search-value-selector>
|
||||
@ -966,14 +944,3 @@
|
||||
Final print template
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<!-- upload file dialog -->
|
||||
<ng-template #uploadDialog>
|
||||
<h1 mat-dialog-title>
|
||||
<span translate>Upload files</span>
|
||||
</h1>
|
||||
<os-media-upload-content
|
||||
(uploadSuccessEvent)="uploadSuccess($event)"
|
||||
(errorEvent)="showUploadError($event)"
|
||||
></os-media-upload-content>
|
||||
</ng-template>
|
||||
|
@ -231,14 +231,3 @@ span {
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.shortened-selector {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
.selector {
|
||||
width: 95%;
|
||||
}
|
||||
.mat-icon-button {
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
|
||||
import { Component, OnInit, OnDestroy, ElementRef, HostListener, TemplateRef } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, ElementRef, HostListener } from '@angular/core';
|
||||
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
|
||||
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||
@ -20,7 +20,6 @@ import { ItemRepositoryService } from 'app/core/repositories/agenda/item-reposit
|
||||
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
||||
import { LocalPermissionsService } from 'app/site/motions/services/local-permissions.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { Motion } from 'app/shared/models/motions/motion';
|
||||
import {
|
||||
MotionChangeRecommendationDialogComponentData,
|
||||
@ -56,7 +55,6 @@ import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
|
||||
import { ViewCategory } from 'app/site/motions/models/view-category';
|
||||
import { ViewCreateMotion } from 'app/site/motions/models/view-create-motion';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||
import { ViewMotionChangeRecommendation } from 'app/site/motions/models/view-motion-change-recommendation';
|
||||
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
|
||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||
@ -250,11 +248,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
*/
|
||||
public blockObserver: BehaviorSubject<ViewMotionBlock[]>;
|
||||
|
||||
/**
|
||||
* Subject for mediafiles
|
||||
*/
|
||||
public mediafilesObserver: BehaviorSubject<ViewMediafile[]>;
|
||||
|
||||
/**
|
||||
* Subject for tags
|
||||
*/
|
||||
@ -445,7 +438,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
private userRepo: UserRepositoryService,
|
||||
private notifyService: NotifyService,
|
||||
private tagRepo: TagRepositoryService,
|
||||
private mediaFilerepo: MediafileRepositoryService,
|
||||
private workflowRepo: WorkflowRepositoryService,
|
||||
private blockRepo: MotionBlockRepositoryService,
|
||||
private itemRepo: ItemRepositoryService,
|
||||
@ -462,7 +454,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
public ngOnInit(): void {
|
||||
// get required information from the repositories
|
||||
this.tagObserver = this.tagRepo.getViewModelListBehaviorSubject();
|
||||
this.mediafilesObserver = this.mediaFilerepo.getViewModelListBehaviorSubject();
|
||||
this.workflowObserver = this.workflowRepo.getViewModelListBehaviorSubject();
|
||||
this.blockObserver = this.blockRepo.getViewModelListBehaviorSubject();
|
||||
this.motionObserver = this.repo.getViewModelListBehaviorSubject();
|
||||
@ -501,17 +492,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
this.configService
|
||||
.get<boolean>('motions_show_sequential_numbers')
|
||||
.subscribe(shown => (this.showSequential = shown));
|
||||
// disable the selector for attachments if there are none
|
||||
this.mediafilesObserver.subscribe(() => {
|
||||
if (this.contentForm) {
|
||||
const attachmentsCtrl = this.contentForm.get('attachments_id');
|
||||
if (this.mediafilesObserver.value.length === 0) {
|
||||
attachmentsCtrl.disable();
|
||||
} else {
|
||||
attachmentsCtrl.enable();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update statute paragraphs
|
||||
this.statuteRepo.getViewModelListObservable().subscribe(newViewStatuteParagraphs => {
|
||||
@ -1546,30 +1526,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
this.personalNoteService.savePersonalNote(this.motion, this.motion.personalNote).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the upload attachments button
|
||||
*/
|
||||
public onUploadAttachmentsButton(templateRef: TemplateRef<string>): void {
|
||||
this.dialogService.open(templateRef, {
|
||||
maxHeight: '90vh',
|
||||
width: '750px',
|
||||
maxWidth: '90vw'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for successful uploads.
|
||||
* Adds the IDs of the upload process to the mediafile selector
|
||||
*
|
||||
* @param fileIds the ids of the uploads if they were successful
|
||||
*/
|
||||
public uploadSuccess(fileIds: number[]): void {
|
||||
const currentAttachments = this.contentForm.get('attachments_id').value as number[];
|
||||
const newAttachments = [...currentAttachments, ...fileIds];
|
||||
this.contentForm.get('attachments_id').setValue(newAttachments);
|
||||
this.dialogService.closeAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for upload errors
|
||||
*
|
||||
|
@ -68,14 +68,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Attachments -->
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="topicForm"
|
||||
[formControl]="topicForm.get('attachments_id')"
|
||||
[multiple]="true"
|
||||
listname="{{ 'Attachments' | translate }}"
|
||||
[InputListValues]="mediafilesObserver"
|
||||
></os-search-value-selector>
|
||||
<os-attachment-control [controlName]="topicForm.get('attachments_id')" (errorHandler)="raiseError($event)"></os-attachment-control>
|
||||
|
||||
<div *ngIf="newTopic">
|
||||
<!-- Visibility -->
|
||||
@ -93,9 +86,7 @@
|
||||
<div>
|
||||
<os-search-value-selector
|
||||
ngDefaultControl
|
||||
[form]="topicForm"
|
||||
[formControl]="topicForm.get('agenda_parent_id')"
|
||||
[multiple]="false"
|
||||
[includeNone]="true"
|
||||
listname="{{ 'Parent agenda item' | translate }}"
|
||||
[InputListValues]="itemObserver"
|
||||
|
@ -15,10 +15,8 @@ import { BehaviorSubject } from 'rxjs';
|
||||
import { ItemVisibilityChoices } from 'app/shared/models/agenda/item';
|
||||
import { CreateTopic } from '../../models/create-topic';
|
||||
import { Topic } from 'app/shared/models/topics/topic';
|
||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||
import { ViewItem } from 'app/site/agenda/models/view-item';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||
import { ViewItem } from 'app/site/agenda/models/view-item';
|
||||
|
||||
/**
|
||||
* Detail page for topics.
|
||||
@ -49,11 +47,6 @@ export class TopicDetailComponent extends BaseViewComponent {
|
||||
*/
|
||||
public topicForm: FormGroup;
|
||||
|
||||
/**
|
||||
* Subject for mediafiles
|
||||
*/
|
||||
public mediafilesObserver: BehaviorSubject<ViewMediafile[]>;
|
||||
|
||||
/**
|
||||
* Subject for agenda items
|
||||
*/
|
||||
@ -88,7 +81,6 @@ export class TopicDetailComponent extends BaseViewComponent {
|
||||
private repo: TopicRepositoryService,
|
||||
private promptService: PromptService,
|
||||
private operator: OperatorService,
|
||||
private mediafileRepo: MediafileRepositoryService,
|
||||
private itemRepo: ItemRepositoryService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
@ -96,7 +88,6 @@ export class TopicDetailComponent extends BaseViewComponent {
|
||||
this.getTopicByUrl();
|
||||
this.createForm();
|
||||
|
||||
this.mediafilesObserver = this.mediafileRepo.getViewModelListBehaviorSubject();
|
||||
this.itemObserver = this.itemRepo.getViewModelListBehaviorSubject();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user