@firestitch/filter
Version:
1,559 lines (1,555 loc) • 96.8 kB
JavaScript
import { FormsModule } from '@angular/forms';
import { MatIconModule, MatInputModule, MatSelectModule, MatChipsModule, MatAutocompleteModule, MatButtonModule, MatCheckboxModule, MAT_LABEL_GLOBAL_OPTIONS } from '@angular/material';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FsDatePickerModule } from '@firestitch/datepicker';
import { FsChipModule } from '@firestitch/chip';
import { FsLabelModule } from '@firestitch/label';
import { Location, CommonModule } from '@angular/common';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { FsStore, FsStoreModule } from '@firestitch/store';
import { __decorate, __metadata } from 'tslib';
import { Alias, Model } from 'tsmodels';
import { isObservable } from 'rxjs/internal/util/isObservable';
import { isDate, isValid, parse, format, isAfter, subMinutes } from 'date-fns';
import { Subject } from 'rxjs';
import { isEmpty, list, filter, remove, FsCommonModule } from '@firestitch/common';
import { isFunction, isObject, toString, clone, cloneDeep } from 'lodash-es';
import { take, takeUntil, debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
import { Component, EventEmitter, Input, ViewChild, ViewEncapsulation, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, IterableDiffers, Output, KeyValueDiffers, Pipe, NgModule } from '@angular/core';
import { toUTC, simpleFormat, format as format$1 } from '@firestitch/date';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @enum {string} */
const ItemType = {
Text: 'text',
Select: 'select',
Range: 'range',
Date: 'date',
DateTime: 'datetime',
DateRange: 'daterange',
DateTimeRange: 'datetimerange',
AutoComplete: 'autocomplete',
AutoCompleteChips: 'autocompletechips',
Checkbox: 'checkbox',
Chips: 'chips',
};
class FsFilterConfigItem extends Model {
/**
* @param {?=} data
* @param {?=} _config
* @param {?=} _route
* @param {?=} _persists
*/
constructor(data = {}, _config, _route, _persists) {
super();
this._config = _config;
this._route = _route;
this._persists = _persists;
this.initialLoading = false;
this.valueChanged = false;
this._pendingValues = false;
this._fromJSON(data);
}
/**
* @return {?}
*/
get hasPendingValues() {
return this._pendingValues;
}
/**
* @return {?}
*/
get model() {
return this._model;
}
/**
* @param {?} val
* @return {?}
*/
set model(val) {
this._model = val;
this._tmpModel = val;
this.checkIfValueChanged();
}
/**
* @return {?}
*/
get tmpModel() {
return this._tmpModel;
}
/**
* @param {?} val
* @return {?}
*/
set tmpModel(val) {
this._tmpModel = val;
}
/**
* @param {?} data
* @return {?}
*/
_fromJSON(data) {
super._fromJSON(data);
if (this.name && isObject(this.name)) {
this.names = this.name;
this.name = Object.keys(this.names).join('-');
}
if (this._config.persist) {
/** @type {?} */
const persisted = this._persists[this._config.persist.name].data;
if (persisted[this.name]) {
/** @type {?} */
let value = persisted[this.name];
if (value) {
if (this.type === ItemType.DateRange || this.type === ItemType.DateTimeRange) {
value.from = value.from ? toUTC(value.from) : null;
value.to = value.to ? toUTC(value.to) : null;
}
else if (this.type === ItemType.Date ||
this.type === ItemType.DateTime) {
if (!isDate(value) || !isValid(value)) {
value = parse(value, 'yyyy-MM-dd\'T\'HH:mm:ssxxxxx', new Date());
}
}
else if (this.type === ItemType.Checkbox && this.checked !== undefined) {
value = value == this.checked;
}
else if (this.type === ItemType.Select && this.multiple) {
value = clone(value);
}
}
this.model = value;
}
}
this.applyDataFromQuery();
if (isFunction(data.values) &&
this.type !== ItemType.AutoComplete &&
this.type !== ItemType.AutoCompleteChips) {
this.values = data.values();
if (isObservable(this.values)) {
this._pendingValues = true;
}
else {
/** @type {?} */
const values = Array.isArray(this.values) ? ((/** @type {?} */ (this.values))).slice() : this.values;
this.sanitizeItem(values);
}
}
else {
/** @type {?} */
const values = Array.isArray(data.values) ? data.values.slice() : data.values;
this.sanitizeItem(values);
}
}
/**
* @param {?} values
* @return {?}
*/
sanitizeItem(values) {
switch (this.type) {
case ItemType.Text:
break;
case ItemType.Select:
{
this.sanitizeSelectItem(values);
}
break;
case ItemType.Chips:
{
this.sanitizeChipsItem(values);
}
break;
case ItemType.Range:
{
this.sanitizeRange();
}
break;
case ItemType.Checkbox:
{
this.sanitizeCheckbox();
}
break;
}
if (this.model === undefined) {
if (this.type == 'checkbox') {
this.model = this.checked == this.defaultValue;
}
else {
this.model = this.defaultValue;
}
}
if (this.model === undefined) {
if (this.type == 'checkbox') {
this.model = false;
}
else if (this.type == 'select') {
if (this.multiple) {
if (!Array.isArray(this.defaultValue)) {
this.model = [];
}
}
else {
if (this.defaultValue === undefined) {
this.model = '__all';
}
}
}
else if (this.type == ItemType.AutoCompleteChips || this.type == ItemType.Chips) {
this.model = [];
}
}
}
/**
* @param {?} values
* @return {?}
*/
sanitizeSelectItem(values) {
this.values = values;
this.groups = null;
// let data = [];
// if (this.nested) {
// // generate a list of values from objects that have not been nested.
// if (!this.multiple) {
// data.push({value: '__all', name: 'All', depth: 0});
// }
//
// Array.prototype.push.apply(data, this.walkSelectNestedValues(filter, null, this.values));
// } else {
//
// data = this.walkSelectValues(filter, this.values);
// }
// this.values = data;
if (this.isolate) {
for (const index in this.values) {
if (this.values.hasOwnProperty(index)) {
if (!this.values[index]) {
continue;
}
if (this.values[index].value == this.isolate.value) {
this.values.splice(index, 1);
}
}
}
if (Array.isArray(this.model)) {
if (this.model.length == this.values.length) {
this.model = null;
this.isolate.enabled = false;
}
else if (this.model[0] == this.isolate.value) {
this.isolate.enabled = true;
}
}
}
}
/**
* @param {?} values
* @return {?}
*/
sanitizeChipsItem(values) {
this.values = values;
this.groups = null;
// if (this.isolate) {
// for (const index in this.values) {
// if (this.values.hasOwnProperty(index)) {
// if (!this.values[index]) {
// continue;
// }
//
// if (this.values[index].value == this.isolate.value) {
// this.values.splice(index, 1);
// }
// }
// }
//
// if (Array.isArray(this.model)) {
// if (this.model.length == this.values.length) {
// this.model = null;
// this.isolate.enabled = false;
// } else if (this.model[0] == this.isolate.value) {
// this.isolate.enabled = true;
// }
// }
// }
//
// for (const value of this.values) {
//
// if (value.group) {
//
// if (!this.groups) {
// this.groups = {};
// }
//
// if (!this.groups[value.group]) {
// this.groups[value.group] = [];
// }
//
// this.groups[value.group].push(value);
// }
// }
}
/**
* @return {?}
*/
sanitizeCheckbox() {
this.checked = this.checked ? toString(this.checked) : true;
this.unchecked = this.unchecked ? toString(this.unchecked) : false;
this.defaultValue = this.defaultValue === undefined ? this.unchecked : toString(this.defaultValue);
}
/**
* @return {?}
*/
applyDataFromQuery() {
if (this.query) {
/** @type {?} */
let query = this._route.snapshot.queryParams[this.query];
if (query !== undefined) {
query += '';
this.model = query;
if (!query.length) {
this.model = undefined;
}
else if (this.type == 'select' && this.multiple) {
this.model = this.model.split(',');
}
else if (this.type == 'daterange' || this.type == 'datetimerange') {
/** @type {?} */
const parts = this.model.split(',');
this.model = { from: parts[0], to: parts[1] };
}
else if (this.type == 'range') {
/** @type {?} */
const parts = this.model.split(',');
this.model = { min: parts[0], max: parts[1] };
}
}
}
}
/**
* @param {?} value
* @return {?}
*/
updateValue(value) {
switch (this.type) {
case ItemType.Select:
{
if (value === '__all' || value === null) {
this.model = value;
return;
}
/** @type {?} */
let valueExists = null;
/** @type {?} */
let isolated = null;
if (this.multiple) {
isolated = this.isolate && Array.isArray(value) && value[0] === this.isolate.value;
valueExists = Array.isArray(this.values)
? value.every((/**
* @param {?} val
* @return {?}
*/
(val) => {
return this.values.find((/**
* @param {?} valueItem
* @return {?}
*/
(valueItem) => valueItem.value === val));
}))
|| isolated
: false;
}
else {
valueExists = Array.isArray(this.values)
? this.values.some((/**
* @param {?} valueItem
* @return {?}
*/
(valueItem) => valueItem.value === value))
: false;
}
if (valueExists) {
this.model = value;
if (this.isolate) {
this.isolate.enabled = isolated;
}
return;
}
}
break;
case ItemType.Range:
{
this.model = isObject(value) ? Object.assign({}, this.model, value) : {};
}
break;
case ItemType.Chips:
{
this.model = [];
}
break;
case ItemType.Date:
case ItemType.DateTime:
{
this.model = value;
}
break;
case ItemType.AutoCompleteChips:
{
if (Array.isArray(value)) {
this.model.push(...value);
}
else if (isObject(value)) {
this.model.push(value);
}
else {
this.model = [];
}
}
break;
default: {
this.model = value;
}
}
}
/**
* @return {?}
*/
loadRemoteValues() {
if (!this.initialLoading && this._pendingValues) {
this.initialLoading = true;
this.values
.pipe(take(1), takeUntil(this._config.destroy$))
.subscribe((/**
* @param {?} values
* @return {?}
*/
(values) => {
this._pendingValues = false;
this.sanitizeItem(values);
this.initialLoading = false;
}));
}
}
/**
* @return {?}
*/
clear() {
this.valueChanged = false;
this.model = undefined;
switch (this.type) {
case ItemType.AutoComplete:
{
this.model = null;
this.tmpModel = null;
this.search = '';
}
break;
case ItemType.AutoCompleteChips:
case ItemType.Chips:
{
this.model = [];
this.tmpModel = [];
this.search = '';
}
break;
case ItemType.Checkbox:
{
this.model = false;
this.tmpModel = false;
}
break;
case ItemType.Select:
{
if (this.multiple) {
this.model = [];
this.tmpModel = [];
}
else {
this.model = Array.isArray(this.values) && this.values.some((/**
* @param {?} val
* @return {?}
*/
(val) => val.value === '__all'))
? '__all'
: null;
this.tmpModel = this.model;
}
if (this.isolate) {
this.isolate.enabled = false;
}
}
break;
case ItemType.Range:
{
this.model = {};
this.tmpModel = {};
}
break;
case ItemType.Text:
{
this.model = '';
this.tmpModel = '';
}
break;
case ItemType.Date:
case ItemType.DateTime:
{
this.model = null;
this.tmpModel = null;
}
break;
}
}
/**
* @return {?}
*/
checkIfValueChanged() {
switch (this.type) {
case ItemType.AutoCompleteChips:
{
this.valueChanged = this.model && this.model.length;
}
break;
case ItemType.Checkbox:
{
this.valueChanged = this.model && this.model !== false;
}
break;
case ItemType.Select:
{
if (this.multiple) {
this.valueChanged = this.model && this.model.length;
}
else {
/** @type {?} */
const hasAllOption = Array.isArray(this.values) && this.values.some((/**
* @param {?} val
* @return {?}
*/
(val) => val.value === '__all'));
if (hasAllOption && this.model && this.model !== '__all') {
this.valueChanged = true;
}
else {
this.valueChanged = !!this.model;
}
}
}
break;
case ItemType.Range:
{
if (this.model && Object.keys(this.model).length > 0) {
this.valueChanged = true;
}
}
break;
case ItemType.Text:
{
this.valueChanged = this.model && this.model !== '';
}
break;
case ItemType.AutoComplete:
case ItemType.Date:
case ItemType.DateTime:
{
this.valueChanged = !!this.model;
}
break;
default: {
this.valueChanged = false;
}
}
}
/**
* @private
* @return {?}
*/
sanitizeRange() {
if (!this.placeholder) {
this.placeholder = ['Min', 'Max'];
}
if (!this.model) {
this.model = {};
}
}
}
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "name", void 0);
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "type", void 0);
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "label", void 0);
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "chipLabel", void 0);
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "children", void 0);
__decorate([
Alias(),
__metadata("design:type", Boolean)
], FsFilterConfigItem.prototype, "multiple", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "groups", void 0);
__decorate([
Alias(),
__metadata("design:type", Boolean)
], FsFilterConfigItem.prototype, "wait", void 0);
__decorate([
Alias(),
__metadata("design:type", String)
], FsFilterConfigItem.prototype, "query", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "values", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "values$", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "selectedValue", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "isolate", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "names", void 0);
__decorate([
Alias(),
__metadata("design:type", Boolean)
], FsFilterConfigItem.prototype, "primary", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "search", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "unchecked", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "checked", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "alias", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "placeholder", void 0);
__decorate([
Alias('default'),
__metadata("design:type", Object)
], FsFilterConfigItem.prototype, "defaultValue", void 0);
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const SORT_BY_FIELD = 'system_sort_by';
/** @type {?} */
const SORT_DIRECTION_FIELD = 'system_sort_direction';
class FsFilterConfig extends Model {
/**
* @param {?=} data
*/
constructor(data = {}) {
super();
this.load = true;
this.persist = false;
this.inline = false;
this.autofocus = false;
this.chips = false;
this.sortValues = null;
this.sort = null;
this.sortDirection = null;
this.namespace = 'filter';
this.items = [];
this.sortByItem = null;
this.sortDirectionItem = null;
this.searchInput = null;
this.singleTextFilter = false;
this._filtersNames = [];
this._destroy$ = new Subject();
this._fromJSON(data);
}
/**
* @return {?}
*/
get destroy$() {
return this._destroy$.asObservable();
}
/**
* @param {?} items
* @param {?} route
* @param {?} persists
* @return {?}
*/
initItems(items, route, persists) {
if (items && Array.isArray(items)) {
this.items = items.map((/**
* @param {?} item
* @return {?}
*/
(item) => {
if (item && item.name && this._filtersNames.indexOf(item.name) === -1) {
this._filtersNames.push(item.name);
return new FsFilterConfigItem(item, this, route, persists);
}
else {
throw Error('Filter init error. Items name must be uniq.');
}
}));
}
this.initSorting(route, persists);
this.searchInput = this.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => item.type === ItemType.Text));
if (this.items.length === 1 && this.items[0].type === ItemType.Text) {
this.singleTextFilter = true;
}
}
/**
* @param {?} route
* @param {?} persists
* @return {?}
*/
initSorting(route, persists) {
if (this.sortValues) {
/** @type {?} */
const sortByItem = {
name: SORT_BY_FIELD,
type: ItemType.Select,
label: 'Sort By',
values: this.sortValues
};
if (this.sort && this.sort.value) {
sortByItem['default'] = this.sort.value;
}
this.sortByItem = new FsFilterConfigItem(sortByItem, this, route, persists);
/** @type {?} */
const sortDirectionItem = {
name: SORT_DIRECTION_FIELD,
type: ItemType.Select,
label: 'Sort Direction',
values: [
{ name: 'Ascending', value: 'asc' },
{ name: 'Descending', value: 'desc' }
]
};
if (this.sort && this.sort.direction) {
sortDirectionItem['default'] = this.sort.direction;
}
this.sortDirectionItem = new FsFilterConfigItem(sortDirectionItem, this, route, persists);
}
}
/**
* @return {?}
*/
updateModelValues() {
this.items.forEach((/**
* @param {?} filter
* @return {?}
*/
(filter$$1) => {
filter$$1.model = clone(filter$$1.tmpModel);
}));
if (this.sortByItem) {
this.sortByItem.model = clone(this.sortByItem.tmpModel);
}
if (this.sortDirectionItem) {
this.sortDirectionItem.model = clone(this.sortDirectionItem.tmpModel);
}
}
/**
* @param {?=} opts
* @return {?}
*/
gets(opts = {}) {
/** @type {?} */
const query = {};
for (const filter$$1 of this.items) {
/** @type {?} */
let value = clone(filter$$1.model);
if (filter$$1.type == ItemType.Select) {
if (filter$$1.multiple) {
if (filter$$1.isolate) {
if (!Array.isArray(filter$$1.model) || !filter$$1.model.length) {
value = list(filter$$1.values, 'value');
}
}
if (filter$$1.model && filter$$1.model.indexOf('__all') > -1) {
value = null;
}
}
else {
if (filter$$1.isolate) {
if (filter$$1.model == '__all') {
value = list(filter$$1.values, 'value');
}
}
else {
if (filter$$1.model == '__all') {
value = null;
}
}
}
}
else if (filter$$1.type == ItemType.AutoCompleteChips || filter$$1.type === ItemType.Chips) {
if (Array.isArray(filter$$1.model) && filter$$1.model.length && !opts.expand) {
value = list(filter$$1.model, 'value');
}
}
else if (filter$$1.type == ItemType.Checkbox) {
value = filter$$1.model ? filter$$1.checked : filter$$1.unchecked;
}
// @TODO
if (isEmpty(value, { zero: true })) {
continue;
}
if (filter$$1.type == ItemType.Date || filter$$1.type == ItemType.DateTime) {
if (value && isValid(value) && isDate(value)) {
value = simpleFormat(value);
}
}
else if (filter$$1.type == ItemType.DateRange || filter$$1.type == ItemType.DateTimeRange) {
/** @type {?} */
const from = value.from;
/** @type {?} */
const to = value.to;
value = {};
if (from) {
value.from = format(from, 'yyyy-MM-dd\THH:mm:ssxxxxx');
}
if (to) {
value.to = format(to, 'yyyy-MM-dd\THH:mm:ssxxxxx');
}
}
else if (filter$$1.type == ItemType.AutoComplete) {
if (isEmpty(filter$$1.model.value, { zero: true })) {
continue;
}
value = opts.expand ? filter$$1.model : filter$$1.model.value;
}
if (isObject(filter$$1.names) && opts.names !== false) {
for (const key in filter$$1.names) {
if (value[filter$$1.names[key]]) {
query[key] = value[filter$$1.names[key]];
}
}
}
else {
query[filter$$1.name] = value;
}
}
if (opts.flatten) {
for (const name in query) {
if (Array.isArray(query[name])) {
query[name] = query[name].join(',');
}
}
}
return query;
}
/**
* @return {?}
*/
getSort() {
/** @type {?} */
let sortBy = this.getSortByValue();
sortBy = sortBy === '__all' ? null : sortBy;
/** @type {?} */
let sortDirection = this.getSortDirectionValue();
sortDirection = sortDirection === '__all' ? null : sortDirection;
return {
value: sortBy,
direction: sortDirection,
};
}
/**
* @return {?}
*/
getSortByValue() {
return this.sortByItem ? this.sortByItem.model : null;
}
/**
* @return {?}
*/
getSortDirectionValue() {
return this.sortDirectionItem ? this.sortDirectionItem.model : null;
}
/**
* @param {?} sort
* @return {?}
*/
updateSort(sort) {
if (sort.sortBy) {
this.sortByItem.model = sort.sortBy;
}
if (sort.sortDirection) {
this.sortDirectionItem.model = sort.sortDirection;
}
}
/**
* @return {?}
*/
getFilledItems() {
return this.items.reduce((/**
* @param {?} acc
* @param {?} filter
* @return {?}
*/
(acc, filter$$1) => {
switch (filter$$1.type) {
case ItemType.Select:
{
/** @type {?} */
const multipleIsoldated = filter$$1.multiple
&& filter$$1.isolate
&& Array.isArray(filter$$1.model)
&& !!filter$$1.model.length
&& filter$$1.model.indexOf('__all') === -1;
/** @type {?} */
const multipleHasSelectedValues = filter$$1.multiple
&& Array.isArray(filter$$1.model)
&& filter$$1.model.length
&& filter$$1.model.indexOf('__all') === -1;
/** @type {?} */
const selectedValues = !filter$$1.multiple && filter$$1.model && filter$$1.model !== '__all';
if (multipleIsoldated || multipleHasSelectedValues || selectedValues) {
acc.push(filter$$1);
}
}
break;
case ItemType.AutoCompleteChips:
{
if (Array.isArray(filter$$1.model) && filter$$1.model.length) {
acc.push(filter$$1);
}
}
break;
case ItemType.Checkbox:
{
if (filter$$1.model) {
acc.push(filter$$1);
}
}
break;
case ItemType.DateRange:
case ItemType.DateTimeRange:
{
if (filter$$1.model.from || filter$$1.model.to) {
acc.push(filter$$1);
}
}
break;
default: {
if (filter$$1.model &&
filter$$1 !== this.searchInput &&
(!isEmpty(filter$$1.model, { zero: true }) || !isEmpty(filter$$1.model.value, { zero: true }))) {
acc.push(filter$$1);
}
}
}
return acc;
}), []);
}
/**
* @return {?}
*/
filtersClear() {
for (const filter$$1 of this.items) {
filter$$1.clear();
}
if (this.sortByItem) {
if (this.sort) {
this.sortByItem.model = this.sort.value;
}
else {
this.sortByItem.clear();
}
}
if (this.sortDirectionItem) {
if (this.sort) {
this.sortDirectionItem.model = this.sort.direction;
}
else {
this.sortDirectionItem.clear();
}
}
}
/**
* @return {?}
*/
loadValuesForPendingItems() {
this.items
.filter((/**
* @param {?} item
* @return {?}
*/
(item) => item.hasPendingValues))
.forEach((/**
* @param {?} item
* @return {?}
*/
(item) => item.loadRemoteValues()));
}
/**
* @return {?}
*/
destroy() {
this._destroy$.next();
this._destroy$.complete();
}
}
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "load", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "persist", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "inline", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "autofocus", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "chips", void 0);
__decorate([
Alias('sorts'),
__metadata("design:type", Array)
], FsFilterConfig.prototype, "sortValues", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "sort", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "sortDirection", void 0);
__decorate([
Alias(),
__metadata("design:type", Object)
], FsFilterConfig.prototype, "namespace", void 0);
__decorate([
Alias(),
__metadata("design:type", Function)
], FsFilterConfig.prototype, "init", void 0);
__decorate([
Alias(),
__metadata("design:type", Function)
], FsFilterConfig.prototype, "change", void 0);
__decorate([
Alias(),
__metadata("design:type", Function)
], FsFilterConfig.prototype, "reload", void 0);
__decorate([
Alias(),
__metadata("design:type", Function)
], FsFilterConfig.prototype, "sortChange", void 0);
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} obj1
* @param {?} obj2
* @return {?}
*/
function objectsAreEquals(obj1, obj2) {
/** @type {?} */
const oldKeys = Object.keys(obj1);
/** @type {?} */
const currKeys = Object.keys(obj2);
if (oldKeys.length !== currKeys.length) {
return false;
}
for (const key in obj1) {
if (obj1.hasOwnProperty(key)) {
/** @type {?} */
const oldItem = obj1[key];
/** @type {?} */
const currItem = obj2[key];
/** @type {?} */
const isArrays = Array.isArray(oldItem) && Array.isArray(currItem);
/** @type {?} */
const isObjects = isObject(oldItem) && isObject(currItem);
if (isArrays && !arraysAreEquals(oldItem, currItem)) {
return false;
}
else if (isObjects && !objectsAreEquals(oldItem, currItem)) {
return false;
}
else if (!isArrays && !isObjects && oldItem !== currItem) {
return false;
}
}
}
return true;
}
/**
* @param {?} arr1
* @param {?} arr2
* @return {?}
*/
function arraysAreEquals(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
for (const el of arr1) {
if (arr2.indexOf(el) === -1) {
return false;
}
}
return true;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class FilterComponent {
/**
* @param {?} _store
* @param {?} route
* @param {?} location
*/
constructor(_store, route, location) {
this._store = _store;
this.route = route;
this.location = location;
this.filter = null;
this.sortUpdate = null;
this.showSortBy = true;
this.showFilterInput = true;
this.changedFilters = [];
this.searchText = '';
this.persists = null;
this.activeFiltersCount = 0;
this.activeFiltersWithInputCount = 0;
this.showFilterMenu = false;
this.modelChanged = new EventEmitter();
this._searchTextInput = null;
this._firstOpen = true;
this._query = {};
this._sort = {};
}
/**
* @param {?} event
* @return {?}
*/
keyEvent(event) {
if (event.code === 'Escape' && this.showFilterMenu) {
this.changeVisibility(false);
}
}
/**
* @param {?} value
* @return {?}
*/
set searchTextInput(value) {
this._searchTextInput = value;
}
/**
* @return {?}
*/
ngOnInit() {
this.config = new FsFilterConfig(this.filter);
this.restorePersistValues();
this.config.initItems(this.filter.items, this.route, this.persists);
// Set search input value after restore from STORE
this.updateSearchText();
// Count active filters after restore
this.updateFilledCounter();
this.watchSearchInput();
if (this.sortUpdate) {
this.sortUpdate
.pipe(takeUntil(this.config.destroy$))
.subscribe((/**
* @param {?} data
* @return {?}
*/
(data) => {
this.config.updateSort(data);
}));
}
this._query = this.config.gets({ flatten: true });
this._sort = this.config.getSort();
if (this.config.init) {
this.config.init(this._query, this.config.getSort());
}
// Avoid ngChanges error
setTimeout((/**
* @return {?}
*/
() => {
if (this._searchTextInput && this.config.autofocus) {
this._searchTextInput.nativeElement.focus();
}
}));
}
/**
* @return {?}
*/
ngOnDestroy() {
if (this.config) {
this.config.destroy();
}
}
/**
*
* Do update value of some field
*
*
* To update text value just pass new text value
*
* public updateSelectValue(val) {
* this.filterEl.updateValues({ keyword: val });
* }
*
* To update select or observable select you could pass suitable value
*
* public updateSelectValue(val: number) {
* this.filterEl.updateValues({ simple_select: val }, { observable_select: val });
* }
*
* To update checkbox value just pass true/false as value
*
* public updateCheckox(val: boolean) {
* this.filterEl.updateValues({ checkbox: val });
* }
*
* To update range value just pass object with min&max object or just with one of targets
*
* Ex.: { min: 10, max 15 }, { min: 5 }, { max 5 }
*
* public updateRange(val) {
* this.filterEl.updateValues({ range: val });
* }
*
* To update autocomplete just pass object with name/value fields
*
* Ex.: { name: 'John Doe', value: 1 }
*
* public updateAutocomplete(val) {
* this.filterEl.updateValues({ autocomplete_user_id: val });
* }
*
* To update autocompletechips just pass:
*
* 1) object with name/value fields - will be appended to existing set of values
*
* { name: 'John Doe', value: 1 }
*
* 2) array of objects - will be appended to existing set of values
*
* [{ name: 'John Doe', value: 1 }, { name: 'Darya Filipova', value: 2 }]
*
* 3) null - clear existing set of values
*
* public updateAutocomplete(val) {
* this.filterEl.updateValues({ autocompletechips_user_id: val });
* }
*
* @param {?} values
* @param {?=} changeEvent
* @return {?}
*/
updateValues(values, changeEvent = true) {
Object.keys(values).forEach((/**
* @param {?} key
* @return {?}
*/
(key) => {
/** @type {?} */
const filterItem = this.config.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => item.name === key));
if (!filterItem) {
return;
}
filterItem.updateValue(values[key]);
if (filterItem === this.config.searchInput) {
this.updateSearchText();
}
}));
this.updateFilledCounter();
if (changeEvent) {
this.filterChange();
}
}
/**
* @return {?}
*/
watchSearchInput() {
this.modelChanged
.pipe(distinctUntilChanged(), debounceTime(500), takeUntil(this.config.destroy$))
.subscribe((/**
* @param {?} value
* @return {?}
*/
(value) => {
this.config.searchInput.model = value;
this.filterChange();
}));
}
/**
* @param {?} text
* @return {?}
*/
modelChange(text) {
this.modelChanged.next(text);
}
/**
* @param {?} event
* @return {?}
*/
backdropClick(event) {
this.switchFilterVisibility(event);
}
/**
* @return {?}
*/
done() {
this.changeVisibility(false);
}
/**
* @param {?=} event
* @return {?}
*/
switchFilterVisibility(event = null) {
if (event) {
event.stopPropagation();
}
this.changeVisibility(!this.showFilterMenu);
}
/**
* @param {?} event
* @return {?}
*/
filterInputClick(event) {
if (['Enter', 'NumpadEnter', 'Escape'].indexOf(event.code) >= 0) {
return this.changeVisibility(false);
}
this.changeVisibility(true);
}
/**
* @param {?} state
* @return {?}
*/
changeVisibility(state) {
this.showFilterMenu = state;
if (this._firstOpen) {
this.config.loadValuesForPendingItems();
this._firstOpen = false;
}
if (this.showFilterMenu) {
window.document.body.classList.add('fs-filter-open');
}
else {
window.document.body.classList.remove('fs-filter-open');
this.updateFilledCounter();
}
}
/**
* @param {?=} event
* @return {?}
*/
clear(event = null) {
if (event) {
event.stopPropagation();
}
if (this.config.searchInput) {
this.config.searchInput.model = '';
this.modelChange(this.config.searchInput.model);
}
this.searchText = '';
this.changedFilters = [];
this.config.filtersClear();
this.activeFiltersCount = 0;
this.activeFiltersWithInputCount = 0;
this.filterChange();
this.changeVisibility(false);
}
/**
* Close filter window and do change callback
* @return {?}
*/
search() {
this.switchFilterVisibility();
this.filterChange();
}
/**
* Call change callback and apply new filter values
* @return {?}
*/
change() {
this.config.updateModelValues();
/** @type {?} */
const query = this.config.gets({ flatten: true });
/** @type {?} */
const sort = this.config.getSort();
/** @type {?} */
const queryChanged = !objectsAreEquals(this._query, query);
if (queryChanged) {
this._query = query;
this.storePersistValues();
this.updateFilledCounter();
if (this.config.change) {
this.config.change(cloneDeep(query), sort);
}
}
/** @type {?} */
const sortingChanged = ((!sort || !this._sort) && sort !== this._sort)
|| (sort && this._sort && !objectsAreEquals(this._sort, sort));
if (sortingChanged) {
this._sort = sort;
if (this.config.sortChange) {
this.config.sortChange(cloneDeep(query), sort);
}
}
}
/**
* Do update count of filled filters
* @return {?}
*/
updateFilledCounter() {
this.changedFilters = this.config.getFilledItems();
this.changedFilters
.filter((/**
* @param {?} item
* @return {?}
*/
(item) => item.hasPendingValues))
.forEach((/**
* @param {?} item
* @return {?}
*/
(item) => item.loadRemoteValues()));
this.activeFiltersWithInputCount = (this.searchText !== '')
? this.changedFilters.length + 1
: this.changedFilters.length;
}
/**
* Store updated filter data into localstorage
* @param {?=} changedItem
* @return {?}
*/
filterChange(changedItem = null) {
if (changedItem) {
if (changedItem === this.config.searchInput) {
this.searchText = changedItem.model;
}
changedItem.checkIfValueChanged();
}
this.storePersistValues();
this.change();
}
/**
* Just reload with same values
* @param {?} event
* @return {?}
*/
reload(event) {
event.stopPropagation();
/** @type {?} */
const query = this.config.gets({ flatten: true });
if (this.config.reload) {
this.config.reload(cloneDeep(query), this.config.getSort());
}
}
/**
* Restoring values from local storage
* @return {?}
*/
restorePersistValues() {
this.persists = this._store.get(this.config.namespace + '-persist', {});
if (this.persists === undefined) {
this.persists = {};
}
if (this.config.persist) {
if (typeof this.config.persist.persist !== 'object') {
this.config.persist = { name: this.config.persist };
}
if (!this.config.persist.name) {
this.config.persist.name = this.location.path();
}
if (!this.persists[this.config.persist.name] || !this.persists[this.config.persist.name].data) {
this.persists[this.config.persist.name] = { data: {}, date: new Date() };
}
if (this.config.persist.timeout) {
/** @type {?} */
const date = new Date(this.persists[this.config.persist.name].date);
if (isAfter(subMinutes(date, this.config.persist.timeout), new Date())) {
this.persists[this.config.persist.name] = { data: {}, date: new Date() };
}
}
}
}
/**
* Store values to local storage
* @return {?}
*/
storePersistValues() {
if (this.config.persist) {
this.persists[this.config.persist.name] = {
data: this.config.gets({ expand: true, names: false }),
date: new Date()
};
this._store.set(this.config.namespace + '-persist', this.persists, {});
}
}
/**
* Reset filter
* @param {?} item
* @return {?}
*/
resetFilter(item) {
/** @type {?} */
const index = this.changedFilters.indexOf(item);
if (index > -1) {
this.changedFilters.splice(index, 1);
item.clear();
}
this.change();
}
/**
* @private
* @return {?}
*/
updateSearchText() {
if (this.config.searchInput && this.config.searchInput.model) {
this.searchText = this.config.searchInput.model;
}
}
}
FilterComponent.decorators = [
{ type: Component, args: [{
selector: 'fs-filter',
template: "<div class=\"fs-filter\"\n *ngIf=\"config?.items?.length\"\n [ngClass]=\"{\n 'filters-open': showFilterMenu,\n 'no-input': !showFilterInput\n }\">\n <div fxLayou=\"row\" fxLayoutAlign=\"start center\" class=\"menu-filter\" fxFlex=\"1 1 0\">\n <div class=\"menu-filter-input\" fxFlex=\"grow\">\n <div class=\"main-filter-bar\" fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <form autocomplete=\"off\" role=\"presentation\">\n <mat-form-field\n class=\"filter-input-field\"\n (click)=\"changeVisibility(true)\"\n floatLabel=\"never\">\n <span matPrefix><mat-icon matPrefix>search</mat-icon></span>\n\n <input matInput\n [(ngModel)]=\"searchText\"\n name=\"filter-input\"\n #searchTextInput\n (keydown)=\"filterInputClick($event)\"\n class=\"filter-input\"\n (ngModelChange)=\"modelChange(searchText)\">\n\n <mat-placeholder>Search</mat-placeholder>\n <a matSuffix\