UNPKG

novo-elements

Version:

770 lines (762 loc) 181 kB
import * as i0 from '@angular/core'; import { signal, computed, Injectable, InjectionToken, Directive, ContentChild, Input, ViewChildren, ViewChild, input, inject, ElementRef, ChangeDetectionStrategy, ViewEncapsulation, Component, SkipSelf, Optional, HostBinding, forwardRef, viewChild, viewChildren, ContentChildren, NgModule } from '@angular/core'; import * as i3 from '@angular/forms'; import { FormControlName, FormControl, Validators, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms'; import * as i1 from 'novo-elements/services'; import { NovoLabelService } from 'novo-elements/services'; import { Subject, Subscription, merge, interval } from 'rxjs'; import { debounceTime, distinctUntilChanged, takeUntil, startWith, filter, debounce } from 'rxjs/operators'; import { Helpers, BooleanInput } from 'novo-elements/utils'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i5 from 'novo-elements/elements/common'; import { NovoCommonModule, NovoOptionModule, NovoOverlayModule } from 'novo-elements/elements/common'; import * as i5$1 from 'novo-elements/elements/select'; import { NovoSelectElement, NovoSelectModule } from 'novo-elements/elements/select'; import * as i6 from 'novo-elements/elements/field'; import { NovoPickerToggleElement, NovoFieldModule } from 'novo-elements/elements/field'; import * as i8 from 'novo-elements/elements/flex'; import { NovoFlexModule } from 'novo-elements/elements/flex'; import * as i9$3 from 'novo-elements/elements/loading'; import { NovoLoadingModule } from 'novo-elements/elements/loading'; import * as i9$2 from 'novo-elements/elements/select-search'; import { NovoSelectSearchModule } from 'novo-elements/elements/select-search'; import * as i4 from 'novo-elements/elements/places'; import { GooglePlacesModule } from 'novo-elements/elements/places'; import * as i9 from 'novo-elements/elements/icon'; import { NovoIconModule } from 'novo-elements/elements/icon'; import * as i10 from 'novo-elements/elements/chips'; import { NovoChipsModule } from 'novo-elements/elements/chips'; import * as i11 from 'novo-elements/elements/tooltip'; import { NovoTooltipModule } from 'novo-elements/elements/tooltip'; import * as i9$1 from 'novo-elements/elements/radio'; import { NovoRadioModule } from 'novo-elements/elements/radio'; import * as i7 from 'novo-elements/elements/date-picker'; import { NovoDatePickerModule } from 'novo-elements/elements/date-picker'; import * as i8$1 from 'novo-elements/elements/date-time-picker'; import { NovoDateTimePickerModule } from 'novo-elements/elements/date-time-picker'; import * as i4$1 from 'novo-elements/elements/autocomplete'; import { NovoAutoCompleteModule } from 'novo-elements/elements/autocomplete'; import * as i8$2 from 'novo-elements/elements/form'; import { NovoFormModule, NovoFormExtrasModule } from 'novo-elements/elements/form'; import * as i7$1 from 'novo-elements/elements/tabbed-group-picker'; import { NovoTabbedGroupPickerElement, NovoTabbedGroupPickerModule } from 'novo-elements/elements/tabbed-group-picker'; import * as i5$2 from 'novo-elements/elements/button'; import { NovoButtonModule } from 'novo-elements/elements/button'; import * as i8$3 from 'novo-elements/elements/dropdown'; import { NovoDropdownModule } from 'novo-elements/elements/dropdown'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { CdkTableModule } from '@angular/cdk/table'; import { NovoCardModule } from 'novo-elements/elements/card'; import { NovoNonIdealStateModule } from 'novo-elements/elements/non-ideal-state'; import { NovoSearchBoxModule } from 'novo-elements/elements/search'; import { NovoSwitchModule } from 'novo-elements/elements/switch'; import { NovoTabModule } from 'novo-elements/elements/tabs'; var Conjunction; (function (Conjunction) { Conjunction["AND"] = "and"; Conjunction["OR"] = "or"; Conjunction["NOT"] = "not"; })(Conjunction || (Conjunction = {})); var Operator; (function (Operator) { Operator["after"] = "after"; Operator["before"] = "before"; Operator["beginsWith"] = "beginsWith"; Operator["between"] = "between"; Operator["equalTo"] = "equalTo"; Operator["exclude"] = "exclude"; Operator["excludeAny"] = "excludeAny"; Operator["greaterThan"] = "greaterThan"; Operator["include"] = "include"; Operator["includeAll"] = "includeAll"; Operator["includeAny"] = "includeAny"; Operator["insideRadius"] = "insideRadius"; Operator["isEmpty"] = "isEmpty"; Operator["isNull"] = "isNull"; Operator["lessThan"] = "lessThan"; Operator["outsideRadius"] = "outsideRadius"; Operator["radius"] = "radius"; Operator["within"] = "within"; })(Operator || (Operator = {})); var RadiusUnits; (function (RadiusUnits) { RadiusUnits["miles"] = "miles"; RadiusUnits["km"] = "km"; })(RadiusUnits || (RadiusUnits = {})); const defaultEditTypeFn = (field) => { return field.inputType || field.dataType || field.type; }; class QueryBuilderService { /** * Function to determine operator and input templates for a field. Value passed * through the criteria builder Input. */ get editTypeFn() { return this._editTypeFn; } set editTypeFn(value) { this._editTypeFn = value ?? defaultEditTypeFn; this.stateChanges.next(); } /** * The field configuration to control which types of fields are available to select * within the Condition Builder. */ get config() { return this._config; } set config(value) { this._config = value; this.stateChanges.next(); } /** * The configuration to control which types of conjuntions can be used in the query builder. * Value passed through the criteria builder Input * eg. and, or, not */ get allowedGroupings() { return this._allowedGroupings; } set allowedGroupings(value) { this._allowedGroupings = value; this.stateChanges.next(); } constructor(labels) { this.labels = labels; this._customFieldDefs = new Set(); this._fieldDefsByName = new Map(); this.scopes = signal([], ...(ngDevMode ? [{ debugName: "scopes" }] : [])); this.hasMultipleScopes = computed(() => this.scopes()?.length > 1, ...(ngDevMode ? [{ debugName: "hasMultipleScopes" }] : [])); /** * Will dispatch when properties changes, subscribe to this if component should * re-render when props are updated */ this.stateChanges = new Subject(); this._editTypeFn = defaultEditTypeFn; this._config = { fields: [], staticFieldSelection: null, }; } /** Adds a field definition that was not included as part of the content children. */ registerFieldDef(fieldDef) { this._customFieldDefs.add(fieldDef); this._fieldDefsByName.set(fieldDef.name, fieldDef); } /** Removes a field definition that was not included as part of the content children. */ unregisterFieldDef(fieldDef) { this._customFieldDefs.delete(fieldDef); this._fieldDefsByName.delete(fieldDef.name); } getFieldDefsByName() { return this._fieldDefsByName; } getConjunctionLabel(conjunction) { switch (conjunction.replace('$', '').toLowerCase()) { case Conjunction.OR: return this.labels.or; case Conjunction.NOT: return this.labels.not; case Conjunction.AND: default: return this.labels.and; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: QueryBuilderService, deps: [{ token: i1.NovoLabelService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: QueryBuilderService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: QueryBuilderService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.NovoLabelService }] }); const NOVO_QUERY_BUILDER = new InjectionToken('NOVO_QUERY_BUILDER'); const NOVO_CRITERIA_BUILDER = new InjectionToken('NOVO_CRITERIA_BUILDER'); const NOVO_CONDITION_BUILDER = new InjectionToken('NOVO_CONDITION_BUILDER'); /** * Contained within a novoConditionField definition describing what input should be * used to capture the compare value of the Condtion */ class NovoConditionInputDef { constructor(/** @docs-private */ template) { this.template = template; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionInputDef, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: NovoConditionInputDef, isStandalone: false, selector: "[novoConditionInputDef]", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionInputDef, decorators: [{ type: Directive, args: [{ selector: '[novoConditionInputDef]', standalone: false, }] }], ctorParameters: () => [{ type: i0.TemplateRef }] }); /** * Contained within a novoConditionField definition describing what operators should be available. */ class NovoConditionOperatorsDef { constructor(/** @docs-private */ template) { this.template = template; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionOperatorsDef, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: NovoConditionOperatorsDef, isStandalone: false, selector: "[novoConditionOperatorsDef]", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionOperatorsDef, decorators: [{ type: Directive, args: [{ selector: '[novoConditionOperatorsDef]', standalone: false, }] }], ctorParameters: () => [{ type: i0.TemplateRef }] }); /** * Field Field definition for the QueryBuilder. * Defines the inputType and operators to use for the query builder. */ class BaseConditionFieldDef { /** Unique name for this field. */ get name() { return this._name; } set name(name) { this._setNameInput(name); } constructor() { } /** * Overridable method that sets the css classes that will be added to every cell in this * column. * In the future, columnCssClassName will change from type string[] to string and this * will set a single string value. * @docs-private */ _updateFieldCssClassName() { this._fieldCssClassName = [`novo-filter-field-${this.cssClassFriendlyName}`]; } _setNameInput(value) { // If the directive is set without a name (updated programmatically), then this setter will // trigger with an empty string and should not overwrite the programmatically set value. if (value) { this._name = value; this.cssClassFriendlyName = value.replace(/[^a-z0-9_-]/gi, '-'); this._updateFieldCssClassName(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BaseConditionFieldDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: BaseConditionFieldDef, isStandalone: true, inputs: { name: ["novoFilterFieldDef", "name"] }, queries: [{ propertyName: "fieldInput", first: true, predicate: NovoConditionInputDef, descendants: true }, { propertyName: "fieldOperators", first: true, predicate: NovoConditionOperatorsDef, descendants: true }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BaseConditionFieldDef, decorators: [{ type: Directive }], ctorParameters: () => [], propDecorators: { name: [{ type: Input, args: ['novoFilterFieldDef'] }], fieldInput: [{ type: ContentChild, args: [NovoConditionInputDef] }], fieldOperators: [{ type: ContentChild, args: [NovoConditionOperatorsDef] }] } }); class NovoConditionFieldDef extends BaseConditionFieldDef { constructor(qbs) { super(); this.qbs = qbs; } register() { this.qbs.registerFieldDef(this); } unregister() { this.qbs.unregisterFieldDef(this); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionFieldDef, deps: [{ token: QueryBuilderService }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: NovoConditionFieldDef, isStandalone: false, selector: "[novoConditionFieldDef]", usesInheritance: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoConditionFieldDef, decorators: [{ type: Directive, args: [{ selector: '[novoConditionFieldDef]', standalone: false, }] }], ctorParameters: () => [{ type: QueryBuilderService }] }); class AbstractConditionFieldDef { /** Column name that should be used to reference this column. */ get name() { return this._name; } set name(name) { this._name = name; // With Ivy, inputs can be initialized before static query results are // available. In that case, we defer the synchronization until "ngOnInit" fires. this._syncFieldDefName(); } constructor(labels) { this.labels = labels; this.operatorEditGroups = []; } ngOnInit() { this._syncFieldDefName(); this._syncFieldDefOperatorValue(); this._previousOperatorValue = this.defaultOperator; // Need to add self to FilterBuilder because "ContentChildren won't find it" this.fieldDef?.register(); } ngAfterViewInit() { setTimeout(() => { this.frameAfterViewInit(); }); } frameAfterViewInit() { const operatorField = this.formControlsByName.find(formControlDirective => formControlDirective.name === 'operator')?.control; if (operatorField) { this._previousOperatorValue = operatorField.value; } } ngOnDestroy() { this.fieldDef?.unregister(); } /** * Define an edit group of operators. Once defined, if the user switches from one of these operators to another, * then the condition value will not be cleared. This makes sense if both operators use the same UI controls for editing. * @param operators The set of Operator values intended to share UI controls. */ defineOperatorEditGroup(...operators) { this.operatorEditGroups.push(new Set(operators)); } onOperatorSelect(formGroup) { let clearVal = true; if (this._previousOperatorValue && this.operatorEditGroups?.length) { const previousOperatorGroupIndex = this.operatorEditGroups.findIndex(grp => grp.has(this._previousOperatorValue)); const newOperatorValue = formGroup.get('operator').getRawValue(); const newOperatorGroupIndex = this.operatorEditGroups.findIndex(grp => grp.has(newOperatorValue)); if (previousOperatorGroupIndex !== -1 && newOperatorGroupIndex !== -1 && previousOperatorGroupIndex === newOperatorGroupIndex) { clearVal = false; } } this._previousOperatorValue = formGroup.get('operator').value; if (clearVal) { formGroup.get('value').setValue(null); } } /** Synchronizes the column definition name with the text column name. */ _syncFieldDefName() { if (this.fieldDef) { this.fieldDef.name = this.name; } } _syncFieldDefOperatorValue() { if (this.fieldDef) { this.fieldDef.defaultOperator = this.defaultOperator; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AbstractConditionFieldDef, deps: [{ token: i1.NovoLabelService }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: AbstractConditionFieldDef, isStandalone: true, inputs: { name: "name" }, viewQueries: [{ propertyName: "fieldDef", first: true, predicate: NovoConditionFieldDef, descendants: true, static: true }, { propertyName: "formControlsByName", predicate: FormControlName, descendants: true }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AbstractConditionFieldDef, decorators: [{ type: Directive }], ctorParameters: () => [{ type: i1.NovoLabelService }], propDecorators: { name: [{ type: Input }], fieldDef: [{ type: ViewChild, args: [NovoConditionFieldDef, { static: true }] }], formControlsByName: [{ type: ViewChildren, args: [FormControlName] }] } }); /** * Handle selection of field values when a list of options is provided. */ class NovoDefaultAddressConditionDef extends AbstractConditionFieldDef { constructor(labelService) { super(labelService); // Overridable defaults this.defaults = { radiusEnabled: false, radiusUnits: 'miles', }; this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : [])); this.radiusUnits = computed(() => this.config()?.radiusUnits || this.defaults.radiusUnits, ...(ngDevMode ? [{ debugName: "radiusUnits" }] : [])); this.radiusEnabled = computed(() => this.config()?.radiusEnabled || this.defaults.radiusEnabled, ...(ngDevMode ? [{ debugName: "radiusEnabled" }] : [])); this.unitsLabel = computed(() => this.radiusUnits() === RadiusUnits.miles ? this.labels.miles : this.labels.km, ...(ngDevMode ? [{ debugName: "unitsLabel" }] : [])); this.defaultOperator = Operator.includeAny; this.chipListModel = ''; this.term = ''; this._addressChangesSubscription = Subscription.EMPTY; this.element = inject(ElementRef); this.defineOperatorEditGroup(Operator.includeAny, Operator.excludeAny, Operator.insideRadius, Operator.outsideRadius); } ngOnDestroy() { this._addressChangesSubscription.unsubscribe(); } onKeyup(event, viewIndex) { if (!["Escape" /* Key.Escape */, "Enter" /* Key.Enter */].includes(event.key)) { this.openPlacesList(viewIndex); } this.term = event.target.value; } onKeydown(event, viewIndex) { if (!this.placesPicker.dropdownOpen) { this.openPlacesList(viewIndex); this.placesPicker.dropdownOpen = true; } if (["Escape" /* Key.Escape */, "Tab" /* Key.Tab */].includes(event.key)) { this.closePlacesList(viewIndex); } else { this.placesPicker.onKeyDown(event); } } getValue(formGroup) { return formGroup.value.value || []; } getCurrentOverlay(viewIndex) { return this.overlayChildren?.find(item => item.overlayId === viewIndex); } getCurrentInput(viewIndex) { return this.inputChildren?.find(item => item.nativeElement.id === viewIndex); } openPlacesList(viewIndex) { this.getCurrentOverlay(viewIndex)?.openPanel(); } closePlacesList(viewIndex) { this.getCurrentOverlay(viewIndex)?.closePanel(); } selectPlace(event, formGroup, viewIndex) { const valueToAdd = { address_components: event.address_components, formatted_address: event.formatted_address, geometry: event.geometry, name: event.name, postal_codes: event.postal_codes, place_id: event.place_id, types: event.types, }; const current = this.getValue(formGroup); const updated = Array.isArray(current) ? [...current, valueToAdd] : [valueToAdd]; formGroup.get('value').setValue(this.updateRadiusInValues(formGroup, updated)); this.inputChildren.forEach(inputChild => { inputChild.nativeElement.value = ''; }); this.getCurrentInput(viewIndex)?.nativeElement.focus(); this.closePlacesList(viewIndex); } remove(valueToRemove, formGroup, viewIndex) { const current = this.getValue(formGroup); const index = current.indexOf(valueToRemove); if (index >= 0) { const oldValue = [...current]; oldValue.splice(index, 1); formGroup.get('value').setValue(oldValue); } this.closePlacesList(viewIndex); } // Override abstract behavior - allow moving location from includeAny to radius, but when moving the opposite direction, // trim out radius information from the value onOperatorSelect(formGroup) { const previousOperator = this._previousOperatorValue; super.onOperatorSelect(formGroup); if ([previousOperator, formGroup.get('operator').getRawValue()].indexOf(Operator.insideRadius) !== -1 && formGroup.get('value').getRawValue() != null) { formGroup.get('value').setValue(this.updateRadiusInValues(formGroup, this.getValue(formGroup))); } } onRadiusSelect(formGroup, event) { const maxLengthRadius = event.target.value.slice(0, 4); event.target.value = maxLengthRadius; formGroup.get('supportingValue').setValue(maxLengthRadius); // We must dirty the form explicitly to show up as a user modification when it was done programmatically formGroup.get('value').setValue(this.updateRadiusInValues(formGroup, this.getValue(formGroup))); formGroup.markAsDirty(); } updateRadiusInValues(formGroup, values) { return values.map(val => ({ ...val, radius: this.isRadiusOperatorSelected(formGroup) ? this.getRadiusData(formGroup) : undefined, })); } getRadiusData(formGroup) { return { value: formGroup.value.supportingValue, units: this.radiusUnits(), operator: formGroup.value.operator, }; } isRadiusOperatorSelected(formGroup) { return ['insideRadius', 'outsideRadius'].includes(formGroup.get('operator')?.value) && formGroup.value?.supportingValue !== null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoDefaultAddressConditionDef, deps: [{ token: i1.NovoLabelService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: NovoDefaultAddressConditionDef, isStandalone: false, selector: "novo-address-condition-def", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "placesPicker", first: true, predicate: ["placesPicker"], descendants: true }, { propertyName: "overlayChildren", predicate: NovoPickerToggleElement, descendants: true }, { propertyName: "inputChildren", predicate: ["addressInput"], descendants: true }, { propertyName: "addressSideTest", predicate: NovoSelectElement, descendants: true }], usesInheritance: true, ngImport: i0, template: ` <ng-container novoConditionFieldDef> <novo-field *novoConditionOperatorsDef="let formGroup" [formGroup]="formGroup"> <novo-select [placeholder]="labels.operator" formControlName="operator" (onSelect)="onOperatorSelect(formGroup)"> <novo-option value="includeAny">{{ labels.includeAny }}</novo-option> <novo-option value="excludeAny">{{ labels.exclude }}</novo-option> <novo-option value="insideRadius" *ngIf="radiusEnabled()">{{ labels.insideRadius }}</novo-option> <novo-option value="outsideRadius" *ngIf="radiusEnabled()">{{ labels.outsideRadius }}</novo-option> </novo-select> </novo-field> <ng-container *novoConditionInputDef="let formGroup; viewIndex as viewIndex; fieldMeta as meta" [formGroup]="formGroup"> <novo-flex justify="space-between" align="end"> <novo-field #input *ngIf="['radius', 'insideRadius', 'outsideRadius'].includes(formGroup.value.operator)" class="address-radius"> <input novoInput paddingLeft="3px" type="number" min="1" max="9999" step="1" formControlName="supportingValue" #distanceInput (input)="onRadiusSelect(formGroup, $event)" /> <span marginLeft="2px" marginRight="4px" paddingTop="3px">{{ unitsLabel() }}</span> </novo-field> <novo-field #novoField class="address-location"> <novo-chip-list [(ngModel)]="chipListModel" [ngModelOptions]="{ standalone: true }" (click)="openPlacesList(viewIndex)"> <novo-chip *ngFor="let item of formGroup.get('value').value" (removed)="remove(item, formGroup, viewIndex)"> <novo-text ellipsis [tooltip]="item.formatted_address" tooltipOnOverflow>{{ item.formatted_address }}</novo-text> <novo-icon novoChipRemove>close</novo-icon> </novo-chip> <input novoChipInput [id]="viewIndex" [placeholder]="labels.location" (keyup)="onKeyup($event, viewIndex)" (keydown)="onKeydown($event, viewIndex)" [picker]="placesPicker" #addressInput/> </novo-chip-list> <novo-picker-toggle [overlayId]="viewIndex" icon="location" novoSuffix> <google-places-list [term]="term" (select)="selectPlace($event, formGroup, viewIndex)" formControlName="value" #placesPicker/> </novo-picker-toggle> </novo-field> </novo-flex> </ng-container> </ng-container> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i4.PlacesListComponent, selector: "google-places-list", inputs: ["userSettings"], outputs: ["termChange", "select", "matchesUpdated"] }, { kind: "component", type: i5.NovoText, selector: "novo-text,[novo-text]", inputs: ["block"] }, { kind: "directive", type: i5.MarginDirective, selector: "[m],[margin],[marginTop],[marginRight],[marginBottom],[marginLeft],[marginX],[marginY],[mt],[mr],[mb],[ml],[mx],[my]", inputs: ["margin", "m", "marginLeft", "ml", "marginRight", "mr", "marginTop", "mt", "marginBottom", "mb", "marginX", "mx", "marginY", "my"] }, { kind: "directive", type: i5.PaddingDirective, selector: "[p],[padding],[paddingTop],[paddingRight],[paddingBottom],[paddingLeft],[paddingX],[paddingY],[pt],[pr],[pb],[pl],[px],[py]", inputs: ["padding", "p", "paddingLeft", "pl", "paddingRight", "pr", "paddingTop", "pt", "paddingBottom", "pb", "paddingX", "px", "paddingY", "py"] }, { kind: "component", type: i5$1.NovoSelectElement, selector: "novo-select", inputs: ["disabled", "required", "tabIndex", "id", "name", "placeholder", "readonly", "headerConfig", "position", "overlayWidth", "overlayHeight", "displayIcon", "displayWith", "compareWith", "hideLegacyOptions", "value", "multiple", "options"], outputs: ["onSelect", "selectionChange", "valueChange", "openedChange", "opened", "closed"] }, { kind: "component", type: i6.NovoFieldElement, selector: "novo-field", inputs: ["layout", "appearance", "customOverlayOrigin", "width"], outputs: ["valueChanges", "stateChanges"] }, { kind: "directive", type: i6.NovoInput, selector: "input[novoInput], textarea[novoInput], select[novoInput]", inputs: ["disabled", "id", "placeholder", "required", "type", "value", "readonly"], outputs: ["onSelect"] }, { kind: "directive", type: i6.NovoFieldSuffixDirective, selector: "[novoSuffix]" }, { kind: "component", type: i6.NovoPickerToggleElement, selector: "novo-picker-toggle", inputs: ["for", "icon", "tabIndex", "aria-label", "triggerOnFocus", "overlayId", "width", "disabled"], exportAs: ["novoPickerToggle"] }, { kind: "directive", type: i6.NovoPickerDirective, selector: "input[picker]", inputs: ["picker", "autocomplete"] }, { kind: "component", type: i5.NovoOption, selector: "novo-option", inputs: ["selected", "keepOpen", "novoInert", "value", "disabled"], exportAs: ["novoOption"] }, { kind: "component", type: i8.NovoFlexElement, selector: "novo-flex,novo-row", inputs: ["direction", "align", "justify", "wrap", "gap"] }, { kind: "component", type: i9.NovoIconComponent, selector: "novo-icon", inputs: ["raised", "theme", "shape", "color", "size", "smaller", "larger", "alt", "name"] }, { kind: "component", type: i10.NovoChipElement, selector: "novo-chip, [novo-chip]", inputs: ["color", "tabIndex", "size", "type", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"] }, { kind: "directive", type: i10.NovoChipRemove, selector: "[novoChipRemove]" }, { kind: "directive", type: i10.NovoChipInput, selector: "input[novoChipInput]", inputs: ["novoChipInputAddOnBlur", "novoChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["novoChipInputTokenEnd"], exportAs: ["novoChipInput", "novoChipInputFor"] }, { kind: "component", type: i10.NovoChipList, selector: "novo-chip-list", inputs: ["errorStateMatcher", "multiple", "chipsToggleable", "stacked", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["novoChipList"] }, { kind: "directive", type: i11.TooltipDirective, selector: "[tooltip]", inputs: ["tooltip", "tooltipPosition", "tooltipType", "tooltipSize", "tooltipBounce", "tooltipNoAnimate", "tooltipRounded", "tooltipAlways", "tooltipPreline", "removeTooltipArrow", "tooltipAutoPosition", "tooltipIsHTML", "tooltipCloseOnClick", "tooltipOnOverflow", "tooltipActive"] }, { kind: "directive", type: NovoConditionOperatorsDef, selector: "[novoConditionOperatorsDef]" }, { kind: "directive", type: NovoConditionInputDef, selector: "[novoConditionInputDef]" }, { kind: "directive", type: NovoConditionFieldDef, selector: "[novoConditionFieldDef]" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoDefaultAddressConditionDef, decorators: [{ type: Component, args: [{ selector: 'novo-address-condition-def', template: ` <ng-container novoConditionFieldDef> <novo-field *novoConditionOperatorsDef="let formGroup" [formGroup]="formGroup"> <novo-select [placeholder]="labels.operator" formControlName="operator" (onSelect)="onOperatorSelect(formGroup)"> <novo-option value="includeAny">{{ labels.includeAny }}</novo-option> <novo-option value="excludeAny">{{ labels.exclude }}</novo-option> <novo-option value="insideRadius" *ngIf="radiusEnabled()">{{ labels.insideRadius }}</novo-option> <novo-option value="outsideRadius" *ngIf="radiusEnabled()">{{ labels.outsideRadius }}</novo-option> </novo-select> </novo-field> <ng-container *novoConditionInputDef="let formGroup; viewIndex as viewIndex; fieldMeta as meta" [formGroup]="formGroup"> <novo-flex justify="space-between" align="end"> <novo-field #input *ngIf="['radius', 'insideRadius', 'outsideRadius'].includes(formGroup.value.operator)" class="address-radius"> <input novoInput paddingLeft="3px" type="number" min="1" max="9999" step="1" formControlName="supportingValue" #distanceInput (input)="onRadiusSelect(formGroup, $event)" /> <span marginLeft="2px" marginRight="4px" paddingTop="3px">{{ unitsLabel() }}</span> </novo-field> <novo-field #novoField class="address-location"> <novo-chip-list [(ngModel)]="chipListModel" [ngModelOptions]="{ standalone: true }" (click)="openPlacesList(viewIndex)"> <novo-chip *ngFor="let item of formGroup.get('value').value" (removed)="remove(item, formGroup, viewIndex)"> <novo-text ellipsis [tooltip]="item.formatted_address" tooltipOnOverflow>{{ item.formatted_address }}</novo-text> <novo-icon novoChipRemove>close</novo-icon> </novo-chip> <input novoChipInput [id]="viewIndex" [placeholder]="labels.location" (keyup)="onKeyup($event, viewIndex)" (keydown)="onKeydown($event, viewIndex)" [picker]="placesPicker" #addressInput/> </novo-chip-list> <novo-picker-toggle [overlayId]="viewIndex" icon="location" novoSuffix> <google-places-list [term]="term" (select)="selectPlace($event, formGroup, viewIndex)" formControlName="value" #placesPicker/> </novo-picker-toggle> </novo-field> </novo-flex> </ng-container> </ng-container> `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, standalone: false, }] }], ctorParameters: () => [{ type: i1.NovoLabelService }], propDecorators: { overlayChildren: [{ type: ViewChildren, args: [NovoPickerToggleElement] }], inputChildren: [{ type: ViewChildren, args: ['addressInput'] }], placesPicker: [{ type: ViewChild, args: ['placesPicker'] }], addressSideTest: [{ type: ViewChildren, args: [NovoSelectElement] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } }); /** * When constructing a query using a field that is a boolean with only true/false as possible values. */ class NovoDefaultBooleanConditionDef extends AbstractConditionFieldDef { constructor(labelService) { super(labelService); this.defaultOperator = Operator.include; this.defineOperatorEditGroup(Operator.include, Operator.exclude, Operator.isNull); } optIdentify(option) { return option.label; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoDefaultBooleanConditionDef, deps: [{ token: i1.NovoLabelService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NovoDefaultBooleanConditionDef, isStandalone: false, selector: "novo-boolean-condition-def", usesInheritance: true, ngImport: i0, template: ` <ng-container novoConditionFieldDef> <novo-field *novoConditionOperatorsDef="let formGroup; fieldMeta as meta" [formGroup]="formGroup"> <novo-select [placeholder]="labels.operator" formControlName="operator" (onSelect)="onOperatorSelect(formGroup)"> <novo-option value="include">{{ labels.equals }}</novo-option> <novo-option value="exclude">{{ labels.doesNotEqual }}</novo-option> <novo-option value="isNull" *ngIf="!meta?.removeIsEmpty">{{ labels.isEmpty }}</novo-option> </novo-select> </novo-field> <novo-field *novoConditionInputDef="let formGroup; fieldMeta as meta" [style.maxWidth.px]="250" [formGroup]="formGroup"> @let isNull = formGroup.value.operator === 'isNull'; @let useYesNo = isNull || meta.dataType === 'Boolean'; @let customOptions = !isNull && meta.options?.length === 2; @if (customOptions) { <novo-radio-group formControlName="value"> <novo-radio *ngFor="let opt of meta.options; trackBy: optIdentify" [value]="opt.value">{{ opt.label }}</novo-radio> </novo-radio-group> } @else { <novo-radio-group formControlName="value"> <novo-radio [value]="true">{{ useYesNo ? labels.yes : labels.true }}</novo-radio> <novo-radio [value]="false">{{ useYesNo ? labels.no : labels.false }}</novo-radio> </novo-radio-group> } </novo-field> </ng-container> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i5$1.NovoSelectElement, selector: "novo-select", inputs: ["disabled", "required", "tabIndex", "id", "name", "placeholder", "readonly", "headerConfig", "position", "overlayWidth", "overlayHeight", "displayIcon", "displayWith", "compareWith", "hideLegacyOptions", "value", "multiple", "options"], outputs: ["onSelect", "selectionChange", "valueChange", "openedChange", "opened", "closed"] }, { kind: "component", type: i6.NovoFieldElement, selector: "novo-field", inputs: ["layout", "appearance", "customOverlayOrigin", "width"], outputs: ["valueChanges", "stateChanges"] }, { kind: "component", type: i5.NovoOption, selector: "novo-option", inputs: ["selected", "keepOpen", "novoInert", "value", "disabled"], exportAs: ["novoOption"] }, { kind: "component", type: i9$1.NovoRadioElement, selector: "novo-radio", inputs: ["id", "name", "tabindex", "vertical", "label", "button", "theme", "size", "icon", "color", "disabled", "checked", "value"], outputs: ["change", "blur", "focus"] }, { kind: "component", type: i9$1.NovoRadioGroup, selector: "novo-radio-group", inputs: ["id", "tabindex", "errorStateMatcher", "appearance", "value", "name", "disabled", "required", "placeholder"], outputs: ["change", "blur"] }, { kind: "directive", type: NovoConditionOperatorsDef, selector: "[novoConditionOperatorsDef]" }, { kind: "directive", type: NovoConditionInputDef, selector: "[novoConditionInputDef]" }, { kind: "directive", type: NovoConditionFieldDef, selector: "[novoConditionFieldDef]" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoDefaultBooleanConditionDef, decorators: [{ type: Component, args: [{ selector: 'novo-boolean-condition-def', template: ` <ng-container novoConditionFieldDef> <novo-field *novoConditionOperatorsDef="let formGroup; fieldMeta as meta" [formGroup]="formGroup"> <novo-select [placeholder]="labels.operator" formControlName="operator" (onSelect)="onOperatorSelect(formGroup)"> <novo-option value="include">{{ labels.equals }}</novo-option> <novo-option value="exclude">{{ labels.doesNotEqual }}</novo-option> <novo-option value="isNull" *ngIf="!meta?.removeIsEmpty">{{ labels.isEmpty }}</novo-option> </novo-select> </novo-field> <novo-field *novoConditionInputDef="let formGroup; fieldMeta as meta" [style.maxWidth.px]="250" [formGroup]="formGroup"> @let isNull = formGroup.value.operator === 'isNull'; @let useYesNo = isNull || meta.dataType === 'Boolean'; @let customOptions = !isNull && meta.options?.length === 2; @if (customOptions) { <novo-radio-group formControlName="value"> <novo-radio *ngFor="let opt of meta.options; trackBy: optIdentify" [value]="opt.value">{{ opt.label }}</novo-radio> </novo-radio-group> } @else { <novo-radio-group formControlName="value"> <novo-radio [value]="true">{{ useYesNo ? labels.yes : labels.true }}</novo-radio> <novo-radio [value]="false">{{ useYesNo ? labels.no : labels.false }}</novo-radio> </novo-radio-group> } </novo-field> </ng-container> `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, standalone: false, }] }], ctorParameters: () => [{ type: i1.NovoLabelService }] }); /** * Most complicated of the default conditions defs, a date needs to provide a different * input type depending on the operator selected. */ class NovoDefaultDateConditionDef extends AbstractConditionFieldDef { constructor(labelService) { super(labelService); this.defaultOperator = Operator.within; this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : [])); this.defineOperatorEditGroup(Operator.before, Operator.after, Operator.equalTo); } closePanel(event, viewIndex) { const overlay = this.overlayChildren.find(item => item.overlayId === viewIndex); overlay.closePanel(event); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NovoDefaultDateConditionDef, deps: [{ token: i1.NovoLabelService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: NovoDefaultDateConditionDef, isStandalone: false, selector: "novo-date-condition-def", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "overlayChildren", predicate: NovoPickerToggleElement, descendants: true }], usesInheritance: true, ngImport: i0, template: ` <ng-container novoConditionFieldDef="DATE"> <novo-field *novoConditionOperatorsDef="let formGroup; fieldMeta as meta" [formGroup]="formGroup"> <novo-select [placeholder]="labels.operator" formControlName="operator" (onSelect)="onOperatorSelect(formGroup)"> <novo-option value="before">{{ labels.before }}</novo-option> <novo-option value="after">{{ labels.after }}</novo-option> <novo-option value="equalTo">{{ labels.equals }}</novo-option> <novo-option value="within">{{ labels.within }}</novo-option> <novo-option value="between">{{ labels.between }}</novo-option> <novo-option value="isNull" *ngIf="!meta?.removeIsEmpty">{{ labels.isEmpty }}</novo-option> </novo-select> </novo-field> <ng-container *novoConditionInputDef="let formGroup; viewIndex as viewIndex" [ngSwitch]="formGroup.value.operator" [formGroup]="formGroup"> <novo-field *novoSwitchCases="['before', 'after', 'equalTo']"> <input novoInput dateFormat="yyyy-mm-dd" [picker]="datepicker" formControlName="value"/> <novo-picker-toggle triggerOnFocus [overlayId]="viewIndex" novoSuffix icon="calendar"> <novo-date-picker #datepicker (onSelect)="closePanel($event, viewIndex)" [weekStart]="config()?.weekStart"></novo-date-picker> </novo-picker-toggle> </novo-field> <novo-field *novoSwitchCases="['between']"> <input novoInput dateRangeFormat="date" [picker]="daterangepicker" formControlName="value"/> <novo-picker-toggle [for]="daterangepicker" triggerOnFocus [overlayId]="viewIndex" novoSuffix icon="calendar"> <novo-date-picker #daterangepicker (onSelect)="closePanel($event, viewIndex)" [weekStart]="config()?.weekStart" mode="range" numberOfMonths="2"></novo-date-picker> </novo-picker-toggle> </novo-field> <novo-field *novoSwitchCases="['within']"> <novo-select [placeholder]="labels.selectDateRange" formControlName="value"> <novo-option value="future">{{ labels.future }}</novo-option> <novo-option value="-1">{{ labels.past1Day }}</novo-option> <novo-option value="-7">{{ labels.past7Days }}</novo-option> <novo-option value="-14">{{ labels.past14Days }}</novo-option> <novo-option value="-21">{{ labels.past21Days }}</novo-option> <novo-option value="-30">{{ labels.past30Days }}</novo-option> <novo-option value="-60">{{ labels.past60Days }}</novo-option> <novo-option value="-90">{{ labels.past90Days }}</novo-option> <novo-option value="-180">{{ labels.past180Days }}</novo-option> <novo-option value="-270">{{ labels.past270Days }}</novo-option> <novo-option value="-365">{{ labels.past1Year }}</novo-option> <novo-option value="1">{{ labels.next1Day }}</novo-option> <novo-option value="7">{{ labels.next7Days }}</novo-option> <novo-option value="14">{{ labels.next14Days }}</novo-option> <novo-option value="21">{{ labels.next21Days }}</novo-option> <novo-option value="30">{{ labels.next30Days }}</novo-option> <novo-option value="60">{{ labels.next60Days }}</novo-option> <novo-option value="90">{{ labels.next90Days }}</novo-option> <novo-option value="180">{{ labels.next180Days }}</novo-option> <novo-option value="270">{{ labels.next270Days }}</novo-option> <novo-option value="365">{{ labels.next1Year }}</novo-option> </novo-select> </novo-field> <novo-field *novoSwitchCases="['isNull']"> <novo-radio-group formControlName="value"> <novo-radio [value]="true">{{ labels.yes }}</novo-radio> <novo-radio [value]="false">{{ labels.no }}</novo-radio> </novo-radio-group> </novo-field> </ng-container> </ng-container> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: