373 lines
8.9 KiB
JavaScript
373 lines
8.9 KiB
JavaScript
|
// Helpers
|
||
|
import { wrapInArray, sortItems, deepEqual, groupByProperty, searchItems } from '../../util/helpers';
|
||
|
import Vue from 'vue';
|
||
|
export default Vue.extend({
|
||
|
name: 'v-data',
|
||
|
inheritAttrs: false,
|
||
|
props: {
|
||
|
items: {
|
||
|
type: Array,
|
||
|
default: () => []
|
||
|
},
|
||
|
options: {
|
||
|
type: Object,
|
||
|
default: () => ({})
|
||
|
},
|
||
|
sortBy: {
|
||
|
type: [String, Array],
|
||
|
default: () => []
|
||
|
},
|
||
|
sortDesc: {
|
||
|
type: [Boolean, Array],
|
||
|
default: () => []
|
||
|
},
|
||
|
customSort: {
|
||
|
type: Function,
|
||
|
default: sortItems
|
||
|
},
|
||
|
mustSort: Boolean,
|
||
|
multiSort: Boolean,
|
||
|
page: {
|
||
|
type: Number,
|
||
|
default: 1
|
||
|
},
|
||
|
itemsPerPage: {
|
||
|
type: Number,
|
||
|
default: 10
|
||
|
},
|
||
|
groupBy: {
|
||
|
type: [String, Array],
|
||
|
default: () => []
|
||
|
},
|
||
|
groupDesc: {
|
||
|
type: [Boolean, Array],
|
||
|
default: () => []
|
||
|
},
|
||
|
locale: {
|
||
|
type: String,
|
||
|
default: 'en-US'
|
||
|
},
|
||
|
disableSort: Boolean,
|
||
|
disablePagination: Boolean,
|
||
|
disableFiltering: Boolean,
|
||
|
search: String,
|
||
|
customFilter: {
|
||
|
type: Function,
|
||
|
default: searchItems
|
||
|
},
|
||
|
serverItemsLength: {
|
||
|
type: Number,
|
||
|
default: -1
|
||
|
}
|
||
|
},
|
||
|
|
||
|
data() {
|
||
|
return {
|
||
|
internalOptions: {
|
||
|
page: this.page,
|
||
|
itemsPerPage: this.itemsPerPage,
|
||
|
sortBy: wrapInArray(this.sortBy),
|
||
|
sortDesc: wrapInArray(this.sortDesc),
|
||
|
groupBy: wrapInArray(this.groupBy),
|
||
|
groupDesc: wrapInArray(this.groupDesc),
|
||
|
mustSort: this.mustSort,
|
||
|
multiSort: this.multiSort
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
|
||
|
computed: {
|
||
|
itemsLength() {
|
||
|
return this.serverItemsLength >= 0 ? this.serverItemsLength : this.filteredItems.length;
|
||
|
},
|
||
|
|
||
|
pageCount() {
|
||
|
return this.internalOptions.itemsPerPage === -1 ? 1 : Math.ceil(this.itemsLength / this.internalOptions.itemsPerPage); // TODO: can't use items.length here
|
||
|
},
|
||
|
|
||
|
pageStart() {
|
||
|
if (this.internalOptions.itemsPerPage === -1 || !this.items.length) return 0;
|
||
|
return (this.internalOptions.page - 1) * this.internalOptions.itemsPerPage;
|
||
|
},
|
||
|
|
||
|
pageStop() {
|
||
|
if (this.internalOptions.itemsPerPage === -1) return this.itemsLength;
|
||
|
if (!this.items.length) return 0;
|
||
|
return Math.min(this.itemsLength, this.internalOptions.page * this.internalOptions.itemsPerPage);
|
||
|
},
|
||
|
|
||
|
isGrouped() {
|
||
|
return !!this.internalOptions.groupBy.length;
|
||
|
},
|
||
|
|
||
|
pagination() {
|
||
|
return {
|
||
|
page: this.internalOptions.page,
|
||
|
itemsPerPage: this.internalOptions.itemsPerPage,
|
||
|
pageStart: this.pageStart,
|
||
|
pageStop: this.pageStop,
|
||
|
pageCount: this.pageCount,
|
||
|
itemsLength: this.itemsLength
|
||
|
};
|
||
|
},
|
||
|
|
||
|
filteredItems() {
|
||
|
let items = this.items.slice();
|
||
|
|
||
|
if (!this.disableFiltering && this.serverItemsLength <= 0) {
|
||
|
items = this.customFilter(items, this.search);
|
||
|
}
|
||
|
|
||
|
return items;
|
||
|
},
|
||
|
|
||
|
computedItems() {
|
||
|
let items = this.filteredItems.slice();
|
||
|
|
||
|
if (!this.disableSort && this.serverItemsLength <= 0) {
|
||
|
items = this.sortItems(items);
|
||
|
}
|
||
|
|
||
|
if (!this.disablePagination && this.serverItemsLength <= 0) {
|
||
|
items = this.paginateItems(items);
|
||
|
}
|
||
|
|
||
|
return items;
|
||
|
},
|
||
|
|
||
|
groupedItems() {
|
||
|
return this.isGrouped ? groupByProperty(this.computedItems, this.internalOptions.groupBy[0]) : null;
|
||
|
},
|
||
|
|
||
|
scopedProps() {
|
||
|
const props = {
|
||
|
sort: this.sort,
|
||
|
sortArray: this.sortArray,
|
||
|
group: this.group,
|
||
|
items: this.computedItems,
|
||
|
options: this.internalOptions,
|
||
|
updateOptions: this.updateOptions,
|
||
|
pagination: this.pagination,
|
||
|
groupedItems: this.groupedItems
|
||
|
};
|
||
|
return props;
|
||
|
}
|
||
|
|
||
|
},
|
||
|
watch: {
|
||
|
options: {
|
||
|
handler(options, old) {
|
||
|
if (deepEqual(options, old)) return;
|
||
|
this.updateOptions(options);
|
||
|
},
|
||
|
|
||
|
deep: true,
|
||
|
immediate: true
|
||
|
},
|
||
|
internalOptions: {
|
||
|
handler(options, old) {
|
||
|
if (deepEqual(options, old)) return;
|
||
|
this.$emit('update:options', options);
|
||
|
this.$emit('pagination', this.pagination);
|
||
|
},
|
||
|
|
||
|
deep: true,
|
||
|
immediate: true
|
||
|
},
|
||
|
|
||
|
page(page) {
|
||
|
this.updateOptions({
|
||
|
page
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.page'(page) {
|
||
|
this.$emit('update:page', page);
|
||
|
},
|
||
|
|
||
|
itemsPerPage(itemsPerPage) {
|
||
|
this.updateOptions({
|
||
|
itemsPerPage
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.itemsPerPage'(itemsPerPage) {
|
||
|
this.$emit('update:items-per-page', itemsPerPage);
|
||
|
},
|
||
|
|
||
|
sortBy(sortBy) {
|
||
|
this.updateOptions({
|
||
|
sortBy: wrapInArray(sortBy)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.sortBy'(sortBy, old) {
|
||
|
!deepEqual(sortBy, old) && this.$emit('update:sort-by', Array.isArray(this.sortBy) ? sortBy : sortBy[0]);
|
||
|
},
|
||
|
|
||
|
sortDesc(sortDesc) {
|
||
|
this.updateOptions({
|
||
|
sortDesc: wrapInArray(sortDesc)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.sortDesc'(sortDesc, old) {
|
||
|
!deepEqual(sortDesc, old) && this.$emit('update:sort-desc', Array.isArray(this.sortDesc) ? sortDesc : sortDesc[0]);
|
||
|
},
|
||
|
|
||
|
groupBy(groupBy) {
|
||
|
this.updateOptions({
|
||
|
groupBy: wrapInArray(groupBy)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.groupBy'(groupBy, old) {
|
||
|
!deepEqual(groupBy, old) && this.$emit('update:group-by', Array.isArray(this.groupBy) ? groupBy : groupBy[0]);
|
||
|
},
|
||
|
|
||
|
groupDesc(groupDesc) {
|
||
|
this.updateOptions({
|
||
|
groupDesc: wrapInArray(groupDesc)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.groupDesc'(groupDesc, old) {
|
||
|
!deepEqual(groupDesc, old) && this.$emit('update:group-desc', Array.isArray(this.groupDesc) ? groupDesc : groupDesc[0]);
|
||
|
},
|
||
|
|
||
|
multiSort(multiSort) {
|
||
|
this.updateOptions({
|
||
|
multiSort
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.multiSort'(multiSort) {
|
||
|
this.$emit('update:multi-sort', multiSort);
|
||
|
},
|
||
|
|
||
|
mustSort(mustSort) {
|
||
|
this.updateOptions({
|
||
|
mustSort
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'internalOptions.mustSort'(mustSort) {
|
||
|
this.$emit('update:must-sort', mustSort);
|
||
|
},
|
||
|
|
||
|
pageCount: {
|
||
|
handler(pageCount) {
|
||
|
this.$emit('page-count', pageCount);
|
||
|
},
|
||
|
|
||
|
immediate: true
|
||
|
},
|
||
|
computedItems: {
|
||
|
handler(computedItems) {
|
||
|
this.$emit('current-items', computedItems);
|
||
|
},
|
||
|
|
||
|
immediate: true
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
toggle(key, oldBy, oldDesc, page, mustSort, multiSort) {
|
||
|
let by = oldBy.slice();
|
||
|
let desc = oldDesc.slice();
|
||
|
const byIndex = by.findIndex(k => k === key);
|
||
|
|
||
|
if (byIndex < 0) {
|
||
|
if (!multiSort) {
|
||
|
by = [];
|
||
|
desc = [];
|
||
|
}
|
||
|
|
||
|
by.push(key);
|
||
|
desc.push(false);
|
||
|
} else if (byIndex >= 0 && !desc[byIndex]) {
|
||
|
desc[byIndex] = true;
|
||
|
} else if (!mustSort) {
|
||
|
by.splice(byIndex, 1);
|
||
|
desc.splice(byIndex, 1);
|
||
|
} else {
|
||
|
desc[byIndex] = false;
|
||
|
} // Reset page to 1 if sortBy or sortDesc have changed
|
||
|
|
||
|
|
||
|
if (!deepEqual(by, oldBy) || !deepEqual(desc, oldDesc)) {
|
||
|
page = 1;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
by,
|
||
|
desc,
|
||
|
page
|
||
|
};
|
||
|
},
|
||
|
|
||
|
group(key) {
|
||
|
const {
|
||
|
by: groupBy,
|
||
|
desc: groupDesc,
|
||
|
page
|
||
|
} = this.toggle(key, this.internalOptions.groupBy, this.internalOptions.groupDesc, this.internalOptions.page, true, false);
|
||
|
this.updateOptions({
|
||
|
groupBy,
|
||
|
groupDesc,
|
||
|
page
|
||
|
});
|
||
|
},
|
||
|
|
||
|
sort(key) {
|
||
|
if (Array.isArray(key)) return this.sortArray(key);
|
||
|
const {
|
||
|
by: sortBy,
|
||
|
desc: sortDesc,
|
||
|
page
|
||
|
} = this.toggle(key, this.internalOptions.sortBy, this.internalOptions.sortDesc, this.internalOptions.page, this.mustSort, this.multiSort);
|
||
|
this.updateOptions({
|
||
|
sortBy,
|
||
|
sortDesc,
|
||
|
page
|
||
|
});
|
||
|
},
|
||
|
|
||
|
sortArray(sortBy) {
|
||
|
const sortDesc = sortBy.map(s => {
|
||
|
const i = this.internalOptions.sortBy.findIndex(k => k === s);
|
||
|
return i > -1 ? this.internalOptions.sortDesc[i] : false;
|
||
|
});
|
||
|
this.updateOptions({
|
||
|
sortBy,
|
||
|
sortDesc
|
||
|
});
|
||
|
},
|
||
|
|
||
|
updateOptions(options) {
|
||
|
this.internalOptions = { ...this.internalOptions,
|
||
|
...options,
|
||
|
page: Math.max(1, Math.min(options.page || this.internalOptions.page, this.pageCount))
|
||
|
};
|
||
|
},
|
||
|
|
||
|
sortItems(items) {
|
||
|
const sortBy = this.internalOptions.groupBy.concat(this.internalOptions.sortBy);
|
||
|
const sortDesc = this.internalOptions.groupDesc.concat(this.internalOptions.sortDesc);
|
||
|
return this.customSort(items, sortBy, sortDesc, this.locale);
|
||
|
},
|
||
|
|
||
|
paginateItems(items) {
|
||
|
// Make sure we don't try to display non-existant page if items suddenly change
|
||
|
// TODO: Could possibly move this to pageStart/pageStop?
|
||
|
if (items.length < this.pageStart) this.internalOptions.page = 1;
|
||
|
return items.slice(this.pageStart, this.pageStop);
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
render() {
|
||
|
return this.$scopedSlots.default && this.$scopedSlots.default(this.scopedProps);
|
||
|
}
|
||
|
|
||
|
});
|
||
|
//# sourceMappingURL=VData.js.map
|