123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- import Vue from 'vue';
- import debounce from 'throttle-debounce/debounce';
- import merge from 'element-ui/src/utils/merge';
- import { orderBy, getColumnById, getRowIdentity } from './util';
- const sortData = (data, states) => {
- const sortingColumn = states.sortingColumn;
- if (!sortingColumn || typeof sortingColumn.sortable === 'string') {
- return data;
- }
- return orderBy(data, states.sortProp, states.sortOrder, sortingColumn.sortMethod, sortingColumn.sortBy);
- };
- const getKeysMap = function(array, rowKey) {
- const arrayMap = {};
- (array || []).forEach((row, index) => {
- arrayMap[getRowIdentity(row, rowKey)] = { row, index };
- });
- return arrayMap;
- };
- const toggleRowSelection = function(states, row, selected) {
- let changed = false;
- const selection = states.selection;
- const index = selection.indexOf(row);
- if (typeof selected === 'undefined') {
- if (index === -1) {
- selection.push(row);
- changed = true;
- } else {
- selection.splice(index, 1);
- changed = true;
- }
- } else {
- if (selected && index === -1) {
- selection.push(row);
- changed = true;
- } else if (!selected && index > -1) {
- selection.splice(index, 1);
- changed = true;
- }
- }
- return changed;
- };
- const toggleRowExpansion = function(states, row, expanded) {
- let changed = false;
- const expandRows = states.expandRows;
- if (typeof expanded !== 'undefined') {
- const index = expandRows.indexOf(row);
- if (expanded) {
- if (index === -1) {
- expandRows.push(row);
- changed = true;
- }
- } else {
- if (index !== -1) {
- expandRows.splice(index, 1);
- changed = true;
- }
- }
- } else {
- const index = expandRows.indexOf(row);
- if (index === -1) {
- expandRows.push(row);
- changed = true;
- } else {
- expandRows.splice(index, 1);
- changed = true;
- }
- }
- return changed;
- };
- const TableStore = function(table, initialState = {}) {
- if (!table) {
- throw new Error('Table is required.');
- }
- this.table = table;
- this.states = {
- rowKey: null,
- _columns: [],
- originColumns: [],
- columns: [],
- fixedColumns: [],
- rightFixedColumns: [],
- leafColumns: [],
- fixedLeafColumns: [],
- rightFixedLeafColumns: [],
- leafColumnsLength: 0,
- fixedLeafColumnsLength: 0,
- rightFixedLeafColumnsLength: 0,
- isComplex: false,
- _data: null,
- filteredData: null,
- data: null,
- sortingColumn: null,
- sortProp: null,
- sortOrder: null,
- isAllSelected: false,
- selection: [],
- reserveSelection: false,
- selectable: null,
- currentRow: null,
- hoverRow: null,
- filters: {},
- expandRows: [],
- defaultExpandAll: false
- };
- for (let prop in initialState) {
- if (initialState.hasOwnProperty(prop) && this.states.hasOwnProperty(prop)) {
- this.states[prop] = initialState[prop];
- }
- }
- };
- TableStore.prototype.mutations = {
- setData(states, data) {
- const dataInstanceChanged = states._data !== data;
- states._data = data;
- Object.keys(states.filters).forEach((columnId) => {
- const values = states.filters[columnId];
- if (!values || values.length === 0) return;
- const column = getColumnById(this.states, columnId);
- if (column && column.filterMethod) {
- data = data.filter((row) => {
- return values.some(value => column.filterMethod.call(null, value, row, column));
- });
- }
- });
- states.filteredData = data;
- states.data = sortData((data || []), states);
- // states.data.forEach((item) => {
- // if (!item.$extra) {
- // Object.defineProperty(item, '$extra', {
- // value: {},
- // enumerable: false
- // });
- // }
- // });
- this.updateCurrentRow();
- if (!states.reserveSelection) {
- if (dataInstanceChanged) {
- this.clearSelection();
- } else {
- this.cleanSelection();
- }
- this.updateAllSelected();
- } else {
- const rowKey = states.rowKey;
- if (rowKey) {
- const selection = states.selection;
- const selectedMap = getKeysMap(selection, rowKey);
- states.data.forEach((row) => {
- const rowId = getRowIdentity(row, rowKey);
- const rowInfo = selectedMap[rowId];
- if (rowInfo) {
- selection[rowInfo.index] = row;
- }
- });
- this.updateAllSelected();
- } else {
- console.warn('WARN: rowKey is required when reserve-selection is enabled.');
- }
- }
- const defaultExpandAll = states.defaultExpandAll;
- if (defaultExpandAll) {
- this.states.expandRows = (states.data || []).slice(0);
- }
- Vue.nextTick(() => this.table.updateScrollY());
- },
- changeSortCondition(states, options) {
- states.data = sortData((states.filteredData || states._data || []), states);
- if (!options || !options.silent) {
- this.table.$emit('sort-change', {
- column: this.states.sortingColumn,
- prop: this.states.sortProp,
- order: this.states.sortOrder
- });
- }
- Vue.nextTick(() => this.table.updateScrollY());
- },
- filterChange(states, options) {
- let { column, values, silent } = options;
- if (values && !Array.isArray(values)) {
- values = [values];
- }
- const prop = column.property;
- const filters = {};
- if (prop) {
- states.filters[column.id] = values;
- filters[column.columnKey || column.id] = values;
- }
- let data = states._data;
- Object.keys(states.filters).forEach((columnId) => {
- const values = states.filters[columnId];
- if (!values || values.length === 0) return;
- const column = getColumnById(this.states, columnId);
- if (column && column.filterMethod) {
- data = data.filter((row) => {
- return values.some(value => column.filterMethod.call(null, value, row, column));
- });
- }
- });
- states.filteredData = data;
- states.data = sortData(data, states);
- if (!silent) {
- this.table.$emit('filter-change', filters);
- }
- Vue.nextTick(() => this.table.updateScrollY());
- },
- insertColumn(states, column, index, parent) {
- let array = states._columns;
- if (parent) {
- array = parent.children;
- if (!array) array = parent.children = [];
- }
- if (typeof index !== 'undefined') {
- array.splice(index, 0, column);
- } else {
- array.push(column);
- }
- if (column.type === 'selection') {
- states.selectable = column.selectable;
- states.reserveSelection = column.reserveSelection;
- }
- this.updateColumns(); // hack for dynamics insert column
- this.scheduleLayout();
- },
- removeColumn(states, column, parent) {
- let array = states._columns;
- if (parent) {
- array = parent.children;
- if (!array) array = parent.children = [];
- }
- if (array) {
- array.splice(array.indexOf(column), 1);
- }
- this.updateColumns(); // hack for dynamics remove column
- this.scheduleLayout();
- },
- setHoverRow(states, row) {
- states.hoverRow = row;
- },
- setCurrentRow(states, row) {
- const oldCurrentRow = states.currentRow;
- states.currentRow = row;
- if (oldCurrentRow !== row) {
- this.table.$emit('current-change', row, oldCurrentRow);
- }
- },
- rowSelectedChanged(states, row) {
- const changed = toggleRowSelection(states, row);
- const selection = states.selection;
- if (changed) {
- const table = this.table;
- table.$emit('selection-change', selection ? selection.slice() : []);
- table.$emit('select', selection, row);
- }
- this.updateAllSelected();
- },
- toggleAllSelection: debounce(10, function(states) {
- const data = states.data || [];
- if (data.length === 0) return;
- const value = !states.isAllSelected;
- const selection = this.states.selection;
- let selectionChanged = false;
- data.forEach((item, index) => {
- if (states.selectable) {
- if (states.selectable.call(null, item, index) && toggleRowSelection(states, item, value)) {
- selectionChanged = true;
- }
- } else {
- if (toggleRowSelection(states, item, value)) {
- selectionChanged = true;
- }
- }
- });
- const table = this.table;
- if (selectionChanged) {
- table.$emit('selection-change', selection ? selection.slice() : []);
- }
- table.$emit('select-all', selection);
- states.isAllSelected = value;
- })
- };
- const doFlattenColumns = (columns) => {
- const result = [];
- columns.forEach((column) => {
- if (column.children) {
- result.push.apply(result, doFlattenColumns(column.children));
- } else {
- result.push(column);
- }
- });
- return result;
- };
- TableStore.prototype.updateColumns = function() {
- const states = this.states;
- const _columns = states._columns || [];
- states.fixedColumns = _columns.filter((column) => column.fixed === true || column.fixed === 'left');
- states.rightFixedColumns = _columns.filter((column) => column.fixed === 'right');
- if (states.fixedColumns.length > 0 && _columns[0] && _columns[0].type === 'selection' && !_columns[0].fixed) {
- _columns[0].fixed = true;
- states.fixedColumns.unshift(_columns[0]);
- }
- const notFixedColumns = _columns.filter(column => !column.fixed);
- states.originColumns = [].concat(states.fixedColumns).concat(notFixedColumns).concat(states.rightFixedColumns);
- const leafColumns = doFlattenColumns(notFixedColumns);
- const fixedLeafColumns = doFlattenColumns(states.fixedColumns);
- const rightFixedLeafColumns = doFlattenColumns(states.rightFixedColumns);
- states.leafColumnsLength = leafColumns.length;
- states.fixedLeafColumnsLength = fixedLeafColumns.length;
- states.rightFixedLeafColumnsLength = rightFixedLeafColumns.length;
- states.columns = [].concat(fixedLeafColumns).concat(leafColumns).concat(rightFixedLeafColumns);
- states.isComplex = states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0;
- };
- TableStore.prototype.isSelected = function(row) {
- return (this.states.selection || []).indexOf(row) > -1;
- };
- TableStore.prototype.clearSelection = function() {
- const states = this.states;
- states.isAllSelected = false;
- const oldSelection = states.selection;
- states.selection = [];
- if (oldSelection.length > 0) {
- this.table.$emit('selection-change', states.selection ? states.selection.slice() : []);
- }
- };
- TableStore.prototype.setExpandRowKeys = function(rowKeys) {
- const expandRows = [];
- const data = this.states.data;
- const rowKey = this.states.rowKey;
- if (!rowKey) throw new Error('[Table] prop row-key should not be empty.');
- const keysMap = getKeysMap(data, rowKey);
- rowKeys.forEach((key) => {
- const info = keysMap[key];
- if (info) {
- expandRows.push(info.row);
- }
- });
- this.states.expandRows = expandRows;
- };
- TableStore.prototype.toggleRowSelection = function(row, selected) {
- const changed = toggleRowSelection(this.states, row, selected);
- if (changed) {
- this.table.$emit('selection-change', this.states.selection ? this.states.selection.slice() : []);
- }
- };
- TableStore.prototype.toggleRowExpansion = function(row, expanded) {
- const changed = toggleRowExpansion(this.states, row, expanded);
- if (changed) {
- this.table.$emit('expand-change', row, this.states.expandRows);
- }
- };
- TableStore.prototype.isRowExpanded = function(row) {
- const { expandRows = [], rowKey } = this.states;
- if (rowKey) {
- const expandMap = getKeysMap(expandRows, rowKey);
- return !!expandMap[getRowIdentity(row, rowKey)];
- }
- return expandRows.indexOf(row) !== -1;
- };
- TableStore.prototype.cleanSelection = function() {
- const selection = this.states.selection || [];
- const data = this.states.data;
- const rowKey = this.states.rowKey;
- let deleted;
- if (rowKey) {
- deleted = [];
- const selectedMap = getKeysMap(selection, rowKey);
- const dataMap = getKeysMap(data, rowKey);
- for (let key in selectedMap) {
- if (selectedMap.hasOwnProperty(key) && !dataMap[key]) {
- deleted.push(selectedMap[key].row);
- }
- }
- } else {
- deleted = selection.filter((item) => {
- return data.indexOf(item) === -1;
- });
- }
- deleted.forEach((deletedItem) => {
- selection.splice(selection.indexOf(deletedItem), 1);
- });
- if (deleted.length) {
- this.table.$emit('selection-change', selection ? selection.slice() : []);
- }
- };
- TableStore.prototype.clearFilter = function() {
- const states = this.states;
- const { tableHeader, fixedTableHeader, rightFixedTableHeader } = this.table.$refs;
- let panels = {};
- if (tableHeader) panels = merge(panels, tableHeader.filterPanels);
- if (fixedTableHeader) panels = merge(panels, fixedTableHeader.filterPanels);
- if (rightFixedTableHeader) panels = merge(panels, rightFixedTableHeader.filterPanels);
- const keys = Object.keys(panels);
- if (!keys.length) return;
- keys.forEach(key => {
- panels[key].filteredValue = [];
- });
- states.filters = {};
- this.commit('filterChange', {
- column: {},
- values: [],
- silent: true
- });
- };
- TableStore.prototype.clearSort = function() {
- const states = this.states;
- if (!states.sortingColumn) return;
- states.sortingColumn.order = null;
- states.sortProp = null;
- states.sortOrder = null;
- this.commit('changeSortCondition', {
- silent: true
- });
- };
- TableStore.prototype.updateAllSelected = function() {
- const states = this.states;
- const { selection, rowKey, selectable, data } = states;
- if (!data || data.length === 0) {
- states.isAllSelected = false;
- return;
- }
- let selectedMap;
- if (rowKey) {
- selectedMap = getKeysMap(states.selection, rowKey);
- }
- const isSelected = function(row) {
- if (selectedMap) {
- return !!selectedMap[getRowIdentity(row, rowKey)];
- } else {
- return selection.indexOf(row) !== -1;
- }
- };
- let isAllSelected = true;
- let selectedCount = 0;
- for (let i = 0, j = data.length; i < j; i++) {
- const item = data[i];
- if (selectable) {
- const isRowSelectable = selectable.call(null, item, i);
- if (isRowSelectable) {
- if (!isSelected(item)) {
- isAllSelected = false;
- break;
- } else {
- selectedCount++;
- }
- }
- } else {
- if (!isSelected(item)) {
- isAllSelected = false;
- break;
- } else {
- selectedCount++;
- }
- }
- }
- if (selectedCount === 0) isAllSelected = false;
- states.isAllSelected = isAllSelected;
- };
- TableStore.prototype.scheduleLayout = function() {
- this.table.debouncedLayout();
- };
- TableStore.prototype.setCurrentRowKey = function(key) {
- const states = this.states;
- const rowKey = states.rowKey;
- if (!rowKey) throw new Error('[Table] row-key should not be empty.');
- const data = states.data || [];
- const keysMap = getKeysMap(data, rowKey);
- const info = keysMap[key];
- if (info) {
- states.currentRow = info.row;
- }
- };
- TableStore.prototype.updateCurrentRow = function() {
- const states = this.states;
- const table = this.table;
- const data = states.data || [];
- const oldCurrentRow = states.currentRow;
- if (data.indexOf(oldCurrentRow) === -1) {
- states.currentRow = null;
- if (states.currentRow !== oldCurrentRow) {
- table.$emit('current-change', null, oldCurrentRow);
- }
- }
- };
- TableStore.prototype.commit = function(name, ...args) {
- const mutations = this.mutations;
- if (mutations[name]) {
- mutations[name].apply(this, [this.states].concat(args));
- } else {
- throw new Error(`Action not found: ${name}`);
- }
- };
- export default TableStore;
|