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); this.userParams = 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.vnComponent('vnArrayModel', { controller: ArrayModel, bindings: { orgData: '