nly-adminlte-vue
Version:
nly adminlte3 components
241 lines (239 loc) • 7.57 kB
JavaScript
import identity from "../../../utils/identity";
import looseEqual from "../../../utils/loose-equal";
import range from "../../../utils/range";
import { isArray, arrayIncludes } from "../../../utils/array";
import { getComponentConfig } from "../../../utils/config";
import { isNumber } from "../../../utils/inspect";
import sanitizeRow from "./sanitize-row";
export default {
props: {
selectable: {
type: Boolean,
default: false
},
selectMode: {
type: String,
default: "multi",
validator: val => arrayIncludes(["range", "multi", "single"], val)
},
selectedVariant: {
type: String,
default: () => getComponentConfig("NlyTable", "selectedVariant")
},
noSelectOnClick: {
// Disable use of click handlers for row selection
type: Boolean,
default: false
}
},
data() {
return {
selectedRows: [],
selectedLastRow: -1
};
},
computed: {
isSelectable() {
return this.selectable && this.selectMode;
},
hasSelectableRowClick() {
return this.isSelectable && !this.noSelectOnClick;
},
supportsSelectableRows() {
return true;
},
selectableHasSelection() {
return (
this.isSelectable &&
this.selectedRows &&
this.selectedRows.length > 0 &&
this.selectedRows.some(identity)
);
},
selectableIsMultiSelect() {
return (
this.isSelectable && arrayIncludes(["range", "multi"], this.selectMode)
);
},
selectableTableClasses() {
return {
"nly-table-selectable": this.isSelectable,
[`nly-table-select-${this.selectMode}`]: this.isSelectable,
"nly-table-selecting": this.selectableHasSelection,
"nly-table-selectable-no-click":
this.isSelectable && !this.hasSelectableRowClick
};
},
selectableTableAttrs() {
return {
// TODO:
// Should this attribute not be included when no-select-on-click is set
// since this attribute implies keyboard navigation?
"aria-multiselectable": !this.isSelectable
? null
: this.selectableIsMultiSelect
? "true"
: "false"
};
}
},
watch: {
computedItems(newVal, oldVal) {
// Reset for selectable
let equal = false;
if (this.isSelectable && this.selectedRows.length > 0) {
// Quick check against array length
equal =
isArray(newVal) && isArray(oldVal) && newVal.length === oldVal.length;
for (let i = 0; equal && i < newVal.length; i++) {
// Look for the first non-loosely equal row, after ignoring reserved fields
equal = looseEqual(sanitizeRow(newVal[i]), sanitizeRow(oldVal[i]));
}
}
if (!equal) {
this.clearSelected();
}
},
selectable(newVal) {
this.clearSelected();
this.setSelectionHandlers(newVal);
},
selectMode() {
this.clearSelected();
},
hasSelectableRowClick(newVal) {
this.clearSelected();
this.setSelectionHandlers(!newVal);
},
selectedRows(selectedRows, oldVal) {
if (this.isSelectable && !looseEqual(selectedRows, oldVal)) {
const items = [];
// `.forEach()` skips over non-existent indices (on sparse arrays)
selectedRows.forEach((v, idx) => {
if (v) {
items.push(this.computedItems[idx]);
}
});
this.$emit("row-selected", items);
}
}
},
beforeMount() {
// Set up handlers if needed
if (this.isSelectable) {
this.setSelectionHandlers(true);
}
},
methods: {
// Public methods
selectRow(index) {
// Select a particular row (indexed based on computedItems)
if (
this.isSelectable &&
isNumber(index) &&
index >= 0 &&
index < this.computedItems.length &&
!this.isRowSelected(index)
) {
const selectedRows = this.selectableIsMultiSelect
? this.selectedRows.slice()
: [];
selectedRows[index] = true;
this.selectedLastClicked = -1;
this.selectedRows = selectedRows;
}
},
unselectRow(index) {
// Un-select a particular row (indexed based on `computedItems`)
if (this.isSelectable && isNumber(index) && this.isRowSelected(index)) {
const selectedRows = this.selectedRows.slice();
selectedRows[index] = false;
this.selectedLastClicked = -1;
this.selectedRows = selectedRows;
}
},
selectAllRows() {
const length = this.computedItems.length;
if (this.isSelectable && length > 0) {
this.selectedLastClicked = -1;
this.selectedRows = this.selectableIsMultiSelect
? range(length).map(() => true)
: [true];
}
},
isRowSelected(index) {
// Determine if a row is selected (indexed based on `computedItems`)
return !!(isNumber(index) && this.selectedRows[index]);
},
clearSelected() {
// Clear any active selected row(s)
this.selectedLastClicked = -1;
this.selectedRows = [];
},
// Internal private methods
selectableRowClasses(index) {
if (this.isSelectable && this.isRowSelected(index)) {
const variant = this.selectedVariant;
return {
"nly-table-row-selected": true,
[`${this.dark ? "bg" : "table"}-${variant}`]: variant
};
} else {
return {};
}
},
selectableRowAttrs(index) {
return {
"aria-selected": !this.isSelectable
? null
: this.isRowSelected(index)
? "true"
: "false"
};
},
setSelectionHandlers(on) {
const method = on && !this.noSelectOnClick ? "$on" : "$off";
// Handle row-clicked event
this[method]("row-clicked", this.selectionHandler);
// Clear selection on filter, pagination, and sort changes
this[method]("filtered", this.clearSelected);
this[method]("context-changed", this.clearSelected);
},
selectionHandler(item, index, evt) {
/* istanbul ignore if: should never happen */
if (!this.isSelectable || this.noSelectOnClick) {
// Don't do anything if table is not in selectable mode
this.clearSelected();
return;
}
const selectMode = this.selectMode;
let selectedRows = this.selectedRows.slice();
let selected = !selectedRows[index];
// Note 'multi' mode needs no special event handling
if (selectMode === "single") {
selectedRows = [];
} else if (selectMode === "range") {
if (this.selectedLastRow > -1 && evt.shiftKey) {
// range
for (
let idx = Math.min(this.selectedLastRow, index);
idx <= Math.max(this.selectedLastRow, index);
idx++
) {
selectedRows[idx] = true;
}
selected = true;
} else {
if (!(evt.ctrlKey || evt.metaKey)) {
// Clear range selection if any
selectedRows = [];
selected = true;
}
this.selectedLastRow = selected ? index : -1;
}
}
selectedRows[index] = selected;
this.selectedRows = selectedRows;
}
}
};