@revolist/revogrid
Version:
Virtual reactive data grid spreadsheet component - RevoGrid.
154 lines (153 loc) • 5.62 kB
JavaScript
/*!
* Built by Revolist OU ❤️
*/
import findIndex from "lodash/findIndex";
import range from "lodash/range";
import { createStore } from "@stencil/store";
import { gatherTrimmedItems, trimmedPlugin } from "./trimmed.plugin";
import { setStore } from "../../utils";
import { proxyPlugin } from "./data.proxy";
/**
* Data store
* Manage the state of a data source and provide methods for updating, adding, and refreshing the data.
*/
export class DataStore {
get store() {
return this.dataStore;
}
constructor(type, storeData) {
const store = (this.dataStore = createStore(Object.assign({ items: [], proxyItems: [], source: [], groupingDepth: 0, groups: {}, type, trimmed: {}, groupingCustomRenderer: undefined }, storeData)));
store.use(proxyPlugin(store));
store.use(trimmedPlugin(store));
}
/**
* full data source update
* @param source - data column/rgRow source
* @param grouping - grouping information if present
* @param silent - if true, store will be updated without resetting trimmed state
* @param preserveTrimmed - if true, current trimmed indexes will be re-applied to the new source, use with caution because physical indexes may change across full data refreshes
*/
updateData(source, grouping,
// if true, store will be updated without resetting trimmed state
silent = false,
// if true, current trimmed indexes will be re-applied to the new source
preserveTrimmed = false) {
const trimmed = this.store.get('trimmed');
const trimmedItems = silent && preserveTrimmed ? gatherTrimmedItems(trimmed) : null;
// during full update we do drop trim
if (!silent) {
this.store.set('trimmed', {});
}
// clear items
this.store.set('items', []);
const items = range(0, (source === null || source === void 0 ? void 0 : source.length) || 0);
// set proxy first
setStore(this.store, {
source,
proxyItems: [...items],
});
// Explicit trim preservation is opt-in because physical indexes may change
// across full data refreshes.
this.store.set('items', trimmedItems ? items.filter(i => !trimmedItems[i]) : items);
// apply grouping if present
if (grouping) {
setStore(this.store, {
groupingDepth: grouping.depth,
// if groups are not provided, we will consider that there is only one group with all items
groups: grouping.groups,
groupingCustomRenderer: grouping.customRenderer,
});
}
}
addTrimmed(some) {
let trimmed = this.store.get('trimmed');
trimmed = Object.assign(Object.assign({}, trimmed), some);
setStore(this.store, { trimmed });
}
setSourceData(items, mutate = true) {
setSourceByVirtualIndex(this.store, items, mutate);
}
// local data update
setData(input) {
const data = Object.assign({}, input);
setStore(this.store, data);
}
refresh() {
const source = this.store.get('source');
this.store.set('source', [...source]);
}
}
/**
* get physical index by virtual
* @param store - store to process
*/
export function getPhysical(store, virtualIndex) {
const items = store.get('items');
return items[virtualIndex];
}
/**
* get all visible items
* @param store - store to process
*/
export function getVisibleSourceItem(store) {
const source = store.get('source');
return store.get('items').map(v => source[v]);
}
/**
* get mapped item from source
* @param store - store to process
* @param virtualIndex - virtual index to process
*/
export const getSourceItem = (store, virtualIndex) => {
const source = store.get('source');
return source[getSourcePhysicalIndex(store, virtualIndex)];
};
/**
* Get physical index from virtual index
*/
export const getSourcePhysicalIndex = (store, virtualIndex) => {
const items = store.get('items');
return items[virtualIndex];
};
/**
* Apply silently item/model/row value to data source
* @param store - data source with changes
* @param modelByIndex - collection of rows/values with virtual indexes to setup/replace in store/data source
* @param mutate - if true, store will be mutated and whole viewport will be re-rendered
*/
export function setSourceByVirtualIndex(store, modelByIndex, mutate = true) {
const items = store.get('items');
const source = store.get('source');
for (let virtualIndex in modelByIndex) {
const realIndex = items[virtualIndex];
const item = modelByIndex[virtualIndex];
source[realIndex] = item;
}
if (mutate) {
store.set('source', [...source]);
}
}
/**
* set item to source
* @param store - store to process
* @param modelByIndex - collection of rows with physical indexes to setup
* @param mutate - if true, store will be mutated and whole viewport will be re-rendered
*/
export function setSourceByPhysicalIndex(store, modelByIndex, mutate = true) {
const source = store.get('source');
for (let index in modelByIndex) {
source[index] = modelByIndex[index];
}
if (mutate) {
store.set('source', [...source]);
}
}
export function setItems(store, items) {
store.set('items', items);
}
export function getSourceItemVirtualIndexByProp(store, prop) {
const items = store.get('items');
const source = store.get('source');
const physicalIndex = findIndex(source, { prop });
return items.indexOf(physicalIndex);
}