UNPKG

nly-adminlte-vue

Version:
241 lines (239 loc) 7.57 kB
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; } } };