mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
[ACS-5183] properties facet file size and file type (#8766)
* ACS-5183 Created component which displays form to search nodes by file type and size * ACS-5183 Validate proper value in number input and allow to use custom file types * ACS-5183 Corrected problem with styles, case insensitive compare for extensions * ACS-5183 Added translations, styles for selecting type, proper comparator for types * ACS-5183 Prevent adding custom file type when selecting existing one * ACS-5183 Corrected bytes for each file size unit and clear number input when value is incorrect * ACS-5183 Added documentation for search properties component, updated documentation for search chip autocomplete input and taking values from settings * ACS-5183 Unit tests * ACS-5183 Added automation ids * ACS-5183 Added missing license header * ACS-5183 Fixed lint issues * ACS-5183 Fixed build issue
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AfterViewChecked, Component, ElementRef, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { FileSizeCondition } from './file-size-condition';
|
||||
import { FileSizeOperator } from './file-size-operator.enum';
|
||||
import { FileSizeUnit } from './file-size-unit.enum';
|
||||
import { Subject } from 'rxjs';
|
||||
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
|
||||
import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
|
||||
import { SearchProperties } from './search-properties';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SearchWidget } from '../../models/search-widget.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-search-properties',
|
||||
templateUrl: './search-properties.component.html',
|
||||
styleUrls: ['./search-properties.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SearchPropertiesComponent implements OnInit, AfterViewChecked, SearchWidget {
|
||||
id: string;
|
||||
settings?: SearchWidgetSettings;
|
||||
context?: SearchQueryBuilderService;
|
||||
startValue: SearchProperties;
|
||||
displayValue$ = new Subject<string>();
|
||||
|
||||
private _form = this.formBuilder.nonNullable.group<FileSizeCondition>({
|
||||
fileSizeOperator: FileSizeOperator.AT_LEAST,
|
||||
fileSize: undefined,
|
||||
fileSizeUnit: FileSizeUnit.KB
|
||||
});
|
||||
private _fileSizeOperators = Object.keys(FileSizeOperator).map<string>(key => FileSizeOperator[key]);
|
||||
private _fileSizeUnits = [FileSizeUnit.KB, FileSizeUnit.MB, FileSizeUnit.GB];
|
||||
private canvas = document.createElement('canvas');
|
||||
private _fileSizeOperatorsMaxWidth: number;
|
||||
private _selectedExtensions: string[];
|
||||
private _reset$ = new Subject<void>();
|
||||
private sizeField: string;
|
||||
private nameField: string;
|
||||
|
||||
@ViewChild('fileSizeOperatorSelect', {read: ElementRef})
|
||||
fileSizeOperatorSelectElement: ElementRef;
|
||||
|
||||
get form(): SearchPropertiesComponent['_form'] {
|
||||
return this._form;
|
||||
}
|
||||
|
||||
get fileSizeOperators(): string[] {
|
||||
return this._fileSizeOperators;
|
||||
}
|
||||
|
||||
get fileSizeUnits(): FileSizeUnit[] {
|
||||
return this._fileSizeUnits;
|
||||
}
|
||||
|
||||
get fileSizeOperatorsMaxWidth(): number {
|
||||
return this._fileSizeOperatorsMaxWidth;
|
||||
}
|
||||
|
||||
get reset$(): Subject<void> {
|
||||
return this._reset$;
|
||||
}
|
||||
|
||||
set selectedExtensions(extensions: string[]) {
|
||||
this._selectedExtensions = extensions;
|
||||
}
|
||||
|
||||
constructor(private formBuilder: FormBuilder, private translateService: TranslateService) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.settings) {
|
||||
if (!this.settings.fileExtensions) {
|
||||
this.settings.fileExtensions = [];
|
||||
}
|
||||
[this.sizeField, this.nameField] = this.settings.field.split(',');
|
||||
}
|
||||
if (this.startValue) {
|
||||
this.setValue(this.startValue);
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
if (this.fileSizeOperatorSelectElement?.nativeElement.clientWidth && !this._fileSizeOperatorsMaxWidth) {
|
||||
setTimeout(() => {
|
||||
const extraFreeSpace = 20;
|
||||
this._fileSizeOperatorsMaxWidth = Math.max(...this._fileSizeOperators.map((operator) =>
|
||||
this.getOperatorNameWidth(operator, this.getCanvasFont(this.fileSizeOperatorSelectElement.nativeElement)))) +
|
||||
this.fileSizeOperatorSelectElement.nativeElement.querySelector('.mat-select-arrow-wrapper').clientWidth +
|
||||
extraFreeSpace;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
narrowDownAllowedCharacters(event: Event) {
|
||||
const value = (event.target as HTMLInputElement).value;
|
||||
if (!(event.target as HTMLInputElement).value) {
|
||||
return;
|
||||
}
|
||||
if ((event as InputEvent).data !== ',' && (event as InputEvent).data !== '.') {
|
||||
(event.target as HTMLInputElement).value = value.replace(/[^0-9.,]/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
clearNumberFieldWhenInvalid(event: FocusEvent) {
|
||||
if (!(event.target as HTMLInputElement).validity.valid) {
|
||||
this.form.controls.fileSize.setValue(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
preventIncorrectNumberCharacters(event: KeyboardEvent): boolean {
|
||||
return event.key !== '-' && event.key !== 'e' && event.key !== '+';
|
||||
}
|
||||
|
||||
compareFileExtensions(extension1: string, extension2: string): boolean {
|
||||
return extension1.toUpperCase() === extension2.toUpperCase();
|
||||
}
|
||||
|
||||
getExtensionWithoutDot(extension: string): string {
|
||||
const extensionSplitByDot = extension.split('.');
|
||||
return extensionSplitByDot[extensionSplitByDot.length - 1];
|
||||
}
|
||||
|
||||
filterExtensions = (extensions: string[], filterValue: string): string[] => {
|
||||
const filterValueLowerCase = this.getExtensionWithoutDot(filterValue).toLowerCase();
|
||||
const extensionWithDot = filterValue.startsWith('.');
|
||||
return extensions.filter((option) => {
|
||||
const optionLowerCase = option.toLowerCase();
|
||||
return extensionWithDot && filterValueLowerCase ? optionLowerCase.startsWith(filterValueLowerCase) : optionLowerCase.includes(filterValue);
|
||||
});
|
||||
};
|
||||
|
||||
reset() {
|
||||
this.form.reset();
|
||||
this.reset$.next();
|
||||
this.displayValue$.next('');
|
||||
}
|
||||
|
||||
submitValues() {
|
||||
if (this.settings && this.context) {
|
||||
let query = '';
|
||||
let displayedValue = '';
|
||||
if (this.form.value.fileSize !== undefined && this.form.value.fileSize !== null) {
|
||||
displayedValue = `${this.translateService.instant(this.form.value.fileSizeOperator)} ${this.form.value.fileSize} ${this.translateService.instant(this.form.value.fileSizeUnit.abbreviation)}`;
|
||||
const size = this.form.value.fileSize * this.form.value.fileSizeUnit.bytes;
|
||||
switch (this.form.value.fileSizeOperator) {
|
||||
case FileSizeOperator.AT_MOST:
|
||||
query = `${this.sizeField}:[0 TO ${size}]`;
|
||||
break;
|
||||
case FileSizeOperator.AT_LEAST:
|
||||
query = `${this.sizeField}:[${size} TO MAX]`;
|
||||
break;
|
||||
default:
|
||||
query = `${this.sizeField}:[${size} TO ${size}]`;
|
||||
}
|
||||
}
|
||||
if (this._selectedExtensions?.length) {
|
||||
if (query) {
|
||||
query += ' AND ';
|
||||
displayedValue += ', ';
|
||||
}
|
||||
query += `${this.nameField}:("*.${this._selectedExtensions.join('" OR "*.')}")`;
|
||||
displayedValue += this._selectedExtensions.join(', ');
|
||||
}
|
||||
this.displayValue$.next(displayedValue);
|
||||
this.context.queryFragments[this.id] = query;
|
||||
this.context.update();
|
||||
}
|
||||
}
|
||||
|
||||
hasValidValue(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
getCurrentValue(): SearchProperties {
|
||||
return {
|
||||
fileSizeCondition: this.form.getRawValue(),
|
||||
fileExtensions: this._selectedExtensions
|
||||
};
|
||||
}
|
||||
|
||||
setValue(searchProperties: SearchProperties) {
|
||||
this.form.patchValue(searchProperties.fileSizeCondition);
|
||||
this.selectedExtensions = searchProperties.fileExtensions;
|
||||
this.submitValues();
|
||||
}
|
||||
|
||||
private getOperatorNameWidth(operator: string, font: string): number {
|
||||
const context = this.canvas.getContext('2d');
|
||||
context.font = font;
|
||||
return context.measureText(this.translateService.instant(operator)).width;
|
||||
}
|
||||
|
||||
private getCssStyle(element: HTMLElement, property: string): string {
|
||||
return window.getComputedStyle(element, null).getPropertyValue(property);
|
||||
}
|
||||
|
||||
private getCanvasFont(el: HTMLElement): string {
|
||||
return `${this.getCssStyle(el, 'font-weight')} ${this.getCssStyle(el, 'font-size')} ${this.getCssStyle(el, 'font-family')}`;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user