salix/front/core/components/array-model/array-model.js

229 lines
5.2 KiB
JavaScript

import ngModule from '../../module';
import ModelProxy from '../model-proxy/model-proxy';
/**
* Model that uses an array as datasource.
*/
export default class ArrayModel extends ModelProxy {
constructor($q, $filter, $element, $scope) {
super($element, $scope);
this.$q = $q;
this.$filter = $filter;
this.autoLoad = true;
this.limit = 0;
this.userFilter = [];
this.clear();
}
$onInit() {
this.autoRefresh();
}
get isLoading() {
return false;
}
autoRefresh() {
if (this.autoLoad)
return this.refresh();
return this.$q.resolve();
}
refresh() {
this.data = this.proccessData(0);
return this.$q.resolve();
}
proccessData(skip) {
if (!this.proxiedData) return null;
let data = this.proxiedData.slice();
let filter = {
order: this.order,
limit: this.limit
};
if (this.where)
filter.where = [this.where];
filter = this.mergeFilters(this.userFilter, filter);
let where = filter.where;
if (where) {
if (!Array.isArray(where))
where = [where];
for (let subWhere of where)
data = this.$filter('filter')(data, subWhere);
}
let order = filter.order;
if (typeof order === 'string')
order = order.split(/\s*,\s*/);
if (Array.isArray(order)) {
let orderComp = [];
for (let field of order) {
let split = field.split(/\s+/);
orderComp.push({
field: split[0],
way: split[1] === 'DESC' ? -1 : 1
});
}
data = data.sort((a, b) => this.sortFunc(a, b, orderComp));
} else if (typeof order === 'function')
data = data.sort(order);
this.skip = skip;
if (filter.limit) {
let end = skip + filter.limit;
this.moreRows = end < data.length;
data = data.slice(this.skip, end);
} else
this.moreRows = false;
this.currentFilter = filter;
return data;
}
applyFilter(user, params) {
this.userFilter = user;
this.userParams = params;
return this.refresh();
}
addFilter(user, params) {
this.userFilter = this.mergeFilters(user, this.userFilter);
Object.assign(this.userParams, params);
return this.refresh();
}
removeFilter() {
return applyFilter(null, null);
}
loadMore() {
if (!this.moreRows)
return this.$q.resolve();
let data = this.proccessData(this.skip + this.currentFilter.limit);
this.data = this.data.concat(data);
return this.$q.resolve();
}
clear() {
this.data = null;
this.userFilter = null;
this.moreRows = false;
this.skip = 0;
}
/**
* Saves current changes on the server.
*
* @return {Promise} The save request promise
*/
save() {
if (this.getChanges())
this.orgData = this.data;
super.save();
return this.$q.resolve();
}
sortFunc(a, b, order) {
for (let i of order) {
let compRes = this.compareFunc(a[i.field], b[i.field]) * i.way;
if (compRes !== 0)
return compRes;
}
return 0;
}
compareFunc(a, b) {
if (a === b)
return 0;
let aType = typeof a;
if (aType === typeof b) {
switch (aType) {
case 'string':
return a.localeCompare(b);
case 'number':
return a - b;
case 'boolean':
return a ? 1 : -1;
case 'object':
if (a instanceof Date && b instanceof Date)
return a.getTime() - b.getTime();
}
}
if (a === undefined)
return -1;
if (b === undefined)
return 1;
if (a === null)
return -1;
if (b === null)
return 1;
return a > b ? 1 : -1;
}
mergeFilters(src, dst) {
let mergedWhere = [];
let wheres = [dst.where, src.where];
for (let where of wheres) {
if (Array.isArray(where))
mergedWhere = mergedWhere.concat(where);
else if (where)
mergedWhere.push(where);
}
switch (mergedWhere.length) {
case 0:
mergedWhere = undefined;
break;
case 1:
mergedWhere = mergedWhere[0];
break;
}
return {
where: mergedWhere,
order: src.order || dst.order,
limit: src.limit || dst.limit
};
}
undoChanges() {
super.undoChanges();
this.refresh();
}
}
ArrayModel.$inject = ['$q', '$filter', '$element', '$scope'];
ngModule.component('vnArrayModel', {
controller: ArrayModel,
bindings: {
orgData: '<?',
data: '=?',
link: '<?',
order: '@?',
limit: '<?',
autoLoad: '<?',
autoSave: '<?'
}
});