@uniquedj95/vtable
Version:
An advanced datatable for Ionic vue framework
780 lines (772 loc) • 34.4 kB
JavaScript
;
var get = require('lodash/get');
var isEmpty = require('lodash/isEmpty');
var orderBy = require('lodash/orderBy');
var vue = require('vue');
var range = require('lodash/range');
var vue$1 = require('@ionic/vue');
var icons = require('ionicons/icons');
var lodash = require('lodash');
/**
* Retrieves an array of rows either from a getter function or the provided default rows.
*
* @param getter - An optional function to retrieve rows asynchronously.
* @param defaultRows - An array of default rows (empty by default).
* @param indexed - If true, adds an 'index' property to each row.
* @returns An array of rows.
*/
async function getRows(defaultRows, indexed = false, getter) {
let rows = defaultRows;
if (typeof getter === 'function')
rows = await getter();
return indexed ? rows.map((r, i) => ({ ...r, index: i + 1 })) : rows;
}
/**
* A function that sort table rows based on specified sort queries
*
* @param rows An array of data
* @param query an array of sort queries
* @returns sorted array
*/
function sortRows(rows, query) {
if (isEmpty(query))
return rows;
const orders = query.map(({ order }) => order);
return orderBy(rows.slice(), query.map(({ column }) => (row) => {
let value = get(row, column.path);
if (!value || isEmpty(value))
return "";
if (typeof column.preSort === "function")
value = column.preSort(value);
if (typeof value === "number" || column.sortCaseSensitive)
return value;
return value.toString().toLowerCase();
}), orders);
}
/**
* Builds pagination information summary
*
* @param paginator The current pagination filter
* @param totalRows Total filtered rows
* @returns string
*/
function buildPaginationInfo(paginator, totalRows) {
const { page, pageSize, totalPages } = paginator;
const from = (page * pageSize) - (pageSize - 1);
const to = (page === totalPages) ? totalRows : page * pageSize;
return totalRows
? `Showing ${from} to ${to} of ${totalRows} entries`
: "No data available";
}
/**
* Calculates the range of visible page numbers for pagination.
*
* @param paginator - The pagination settings.
* @param totalRows - The total number of rows.
* @param pages - An array of current visible page numbers.
* @returns The updated pagination settings.
*/
function calculatePageRange(paginator, totalRows, pages) {
// Calculate the total number of pages
paginator.totalPages = Math.ceil(totalRows / paginator.pageSize);
// If total pages are within visibleBtns, show all pages
if (paginator.totalPages <= paginator.visibleBtns) {
paginator.start = 1;
paginator.end = paginator.totalPages;
return paginator;
}
// Return if start and end page numbers are already visible
if ((pages.includes(paginator.page - 1) || paginator.page === 1) &&
(pages.includes(paginator.page + 1) || paginator.page === paginator.totalPages)) {
return paginator;
}
// Calculate the range of visible page numbers
paginator.start = paginator.page === 1 ? 1 : paginator.page - 1;
paginator.end = paginator.start + paginator.visibleBtns - 5;
// Adjust start and end if they go out of bounds
if (paginator.start <= 3) {
paginator.end += 3 - paginator.start;
paginator.start = 1;
}
if (paginator.end >= paginator.totalPages - 2) {
paginator.start -= paginator.end - (paginator.totalPages - 2);
paginator.end = paginator.totalPages;
}
// Ensure start is within valid range
paginator.start = Math.max(paginator.start, 1);
return paginator;
}
/**
* Paginates an array of rows based on the provided pagination settings.
*
* @param rows - The array of rows to be paginated.
* @param paginator - The pagination settings.
* @returns The paginated array of rows.
*/
function getActiveRows(rows, paginator) {
if (isEmpty(rows))
return rows;
const { page, pageSize } = paginator;
const start = (page - 1) * pageSize;
return rows.slice(start, start + pageSize);
}
/**
* Initializes sort queries based on column configurations.
*
* @param columns - An array of table columns.
* @returns An array of initial sort queries.
*/
function initializeSortQueries(columns) {
return columns.reduce((acc, column) => {
if (column.initialSort)
acc.push({ column, order: column.initialSortOrder || "asc" });
return acc;
}, []);
}
/**
* Updates the array of sort queries based on a specific column.
*
* @param sortQueries - The current array of sort queries.
* @param column - The column for which to update the sort query.
* @returns The updated array of sort queries.
*/
function updateSortQueries(sortQueries, column) {
const i = sortQueries.findIndex(q => q.column.path === column.path);
if (i >= 0)
sortQueries[i].order = sortQueries[i].order === 'asc' ? 'desc' : 'asc';
else
sortQueries = [{ column, order: 'asc' }];
return sortQueries;
}
/**
* Filters an array of rows based on a query string.
*
* @param rows - The array of rows to be filtered.
* @param query - The query string for filtering.
* @returns The filtered array of rows.
*/
function filterRows(rows, query) {
if (!query || isEmpty(rows))
return rows;
return rows.slice().filter(row => Object.values(row).some(v => v && JSON.stringify(v).toLowerCase().includes(query.toLowerCase())));
}
/**
* Determines if a table column is drillable based on the provided column configuration, value, and row.
*
* @param column - The table column configuration object.
* @param value - The value in the table cell.
* @param row - The entire row data.
* @returns A boolean indicating whether the column is drillable.
*/
function isDrillable(column, value, row) {
return typeof column.drillable === 'function'
? column.drillable(value, row)
: !!column.drillable && !isEmpty(value);
}
const SelectInput = vue.defineComponent({
name: "SelectInput",
props: {
value: {
type: Object,
default: () => ({}),
},
label: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "Select Option"
},
options: {
type: Array,
default: () => [],
},
asyncOptions: {
type: Function,
required: false,
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
},
validate: {
type: Function,
required: false
}
},
emits: ["select"],
setup(props, { emit }) {
const selectedOption = vue.ref();
const canShowOptions = vue.ref(false);
const filter = vue.ref('');
const filteredOptions = vue.ref([]);
const errs = vue.ref("");
const errorClass = vue.computed(() => errs.value ? "box-input-error" : "");
const marginTop = vue.computed(() => props.label ? "ion-margin-top" : "");
const tags = vue.computed(() => {
if (props.multiple)
return filteredOptions.value.filter(({ isChecked }) => isChecked);
return selectedOption.value ? [selectedOption.value] : [];
});
const showPlaceholder = vue.computed(() => {
return !filter.value && lodash.isEmpty(tags.value) && !canShowOptions.value;
});
const model = vue.computed({
get: () => props.value,
set: (value) => emit("select", value)
});
const setDefaults = () => {
selectedOption.value = undefined;
if (lodash.isEmpty(model.value))
return;
if (Array.isArray(model.value) && props.multiple) {
model.value.forEach(option => {
const index = filteredOptions.value.findIndex(({ value }) => value === option.value);
if (index === -1) {
filteredOptions.value.push({ ...option, isChecked: true });
}
else {
filteredOptions.value[index].isChecked = true;
}
});
}
selectedOption.value = filteredOptions.value.find(option => {
if (Array.isArray(model.value))
return option.value === model.value[0].value;
return option.value === model.value.value;
});
if (lodash.isEmpty(selectedOption.value)) {
selectedOption.value = Array.isArray(model.value) ? model.value[0] : model.value;
}
};
const filterOptions = async () => {
const filtered = typeof props.asyncOptions === 'function'
? await props.asyncOptions(filter.value)
: props.options.filter(({ label }) => label.toLowerCase().includes(filter.value.toLowerCase()));
tags.value.forEach(tag => {
const index = filtered.findIndex(f => f.value === tag.value);
if (index === -1)
filtered.push(tag);
else
filtered[index].isChecked = true;
});
filteredOptions.value = filtered;
};
const validate = async () => {
if (props.required && lodash.isEmpty(model.value)) {
return errs.value = "This field is required";
}
if (typeof props.validate === 'function') {
const errors = await props.validate(model.value);
if (errors && errors.length) {
errs.value = errors.join(', ');
}
}
return errs.value = "";
};
const onCloseOptions = () => {
canShowOptions.value = false;
model.value = props.multiple ? tags.value : !lodash.isEmpty(tags.value) ? tags.value[0] : {};
filter.value = '';
validate();
};
const showOptions = () => {
if (props.disabled)
return;
canShowOptions.value = true;
errs.value = '';
};
const selectOption = (item) => {
if (!props.multiple) {
selectedOption.value = item;
return onCloseOptions();
}
model.value = props.multiple ? tags.value : !lodash.isEmpty(tags.value) ? tags.value[0] : {};
filter.value = '';
};
const diselectOption = (tag) => {
if (props.multiple)
return tag.isChecked = false;
return selectedOption.value = undefined;
};
const onReset = () => {
filter.value = '';
selectedOption.value = undefined;
filteredOptions.value.forEach(option => option.isChecked = false);
};
vue.watch(() => props.value, () => setDefaults());
vue.watch([filter, () => props.options, () => props.asyncOptions], async () => {
await filterOptions();
setDefaults();
});
vue.onMounted(async () => {
await filterOptions();
setDefaults();
addEventListener('click', (e) => {
const isClosest = e.target.closest('.inner-input-box');
if (!isClosest && canShowOptions.value) {
onCloseOptions();
}
});
});
vue.onBeforeUnmount(() => removeEventListener('click', e => console.log(e)));
return () => [
props.label && vue.h(vue$1.IonLabel, { class: "ion-padding-bottom bold" }, props.label),
vue.h("div", { class: `outer-input-box box-input ${errorClass.value} ${marginTop.value}` }, vue.h("div", { class: "inner-input-box" }, [
vue.h("div", { style: { display: 'flex', flexWrap: 'wrap', width: '100%' }, onClick: showOptions }, [
...tags.value.map(tag => vue.h(vue$1.IonChip, [
vue.h(vue$1.IonLabel, tag.label),
vue.h(vue$1.IonIcon, { icon: icons.closeCircle, color: 'danger', onClick: () => diselectOption(tag), style: { zIndex: 90 } })
])),
vue.h(vue$1.IonInput, {
disabled: props.disabled,
placeholder: showPlaceholder.value ? props.placeholder : '',
class: "search-input",
value: filter.value,
onIonInput: (e) => filter.value = e.target.value
})
]),
canShowOptions.value && vue.h("div", { class: "input-options" }, vue.h(vue$1.IonList, filteredOptions.value.map((option, i) => vue.h(vue$1.IonItem, {
lines: i + 1 === filteredOptions.value.length ? 'none' : undefined,
onClick: () => selectOption(option)
}, [
props.multiple && vue.h(vue$1.IonCheckbox, {
class: "input-option-checkbox",
slot: "start",
value: option.isChecked,
onIonInput: (e) => option.isChecked = e.target.checked
}),
vue.h(vue$1.IonLabel, option.label)
])))),
vue.h("div", { class: "input-icon" }, [
(filter.value || tags.value.length) && vue.h(vue$1.IonIcon, { icon: icons.close, onClick: onReset }),
vue.h(vue$1.IonIcon, {
icon: canShowOptions.value ? icons.chevronUp : icons.chevronDown,
onClick: canShowOptions.value ? onCloseOptions : showOptions
})
].filter(Boolean))
])),
errs.value && vue.h(vue$1.IonNote, { color: "danger" }, errs.value)
];
}
});
const DateRangePicker = vue.defineComponent({
props: {
range: {
type: Object,
default: () => ({ startDate: "", endDate: "" }),
},
},
emits: ["rangeChange"],
setup(props, { emit }) {
const start = vue.ref(props.range.startDate);
const end = vue.ref(props.range.endDate);
const cRange = vue.computed(() => ({ startDate: start.value, endDate: end.value }));
vue.watch(cRange, (v) => emit("rangeChange", v));
return () => vue.h(vue$1.IonGrid, { class: 'ion-no-padding ion-no-margin' }, vue.h(vue$1.IonRow, [
vue.h(vue$1.IonCol, { size: "6" }, vue.h(vue$1.IonInput, { type: 'date', class: 'box-input', value: start.value, onIonInput: (e) => start.value = e.target.value, style: { width: "100%" } })),
vue.h(vue$1.IonCol, { size: '1', style: { display: "flex", justifyContent: "center " } }, vue.h(vue$1.IonIcon, { icon: icons.arrowForward, style: { fontSize: '24px', padding: '.5rem' } })),
vue.h(vue$1.IonCol, { size: "5" }, vue.h(vue$1.IonInput, { type: 'date', class: 'box-input', value: end.value, onIonInput: (e) => end.value = e.target.value, style: { width: "100%" } })),
]));
},
});
const DataTable = vue.defineComponent({
name: "DataTable",
props: {
rows: {
type: Array,
default: () => []
},
asyncRows: {
type: Function,
required: false
},
columns: {
type: Array,
default: () => []
},
actionsButtons: {
type: Array,
default: () => []
},
rowActionsButtons: {
type: Array,
default: () => []
},
customFilters: {
type: Array,
default: () => []
},
color: {
type: String,
},
config: {
type: Object,
default: () => ({})
},
loading: {
type: Boolean,
default: false
}
},
emits: ["customFilter", "queryChange", "drilldown"],
setup(props, { emit, slots }) {
const isLoading = vue.ref(false);
const tableRows = vue.ref([]);
const filteredRows = vue.ref([]);
const totalFilteredRows = vue.computed(() => filteredRows.value.length);
const totalColumns = vue.computed(() => isEmpty(props.rowActionsButtons) ? tableColumns.value.length : tableColumns.value.length + 1);
const paginationPages = vue.computed(() => filters.pagination.enabled ? range(filters.pagination.start, filters.pagination.end + 1) : []);
const tableColumns = vue.computed(() => props.config.showIndices
? [{ path: "index", label: "#", initialSort: true, initialSortOrder: "asc" }, ...props.columns]
: props.columns);
const filters = vue.reactive({
search: "",
sort: [],
pagination: {
enabled: props.config?.pagination?.enabled ?? true,
page: props.config?.pagination?.page ?? 1,
pageSize: props.config?.pagination?.pageSize ?? 10,
start: props.config?.pagination?.start ?? 1,
end: props.config?.pagination?.end ?? 1,
totalPages: props.config?.pagination?.totalPages ?? 1,
visibleBtns: props.config?.pagination?.visibleBtns ?? 7,
pageSizeOptions: props.config?.pagination?.pageSizeOptions ?? [5, 10, 20, 50, 100]
}
});
const activeRows = vue.ref([]);
const showFilterSection = vue.computed(() => {
return props.config.showSearchField !== false ||
props.customFilters.length > 0 ||
props.actionsButtons.length > 0;
});
const customFiltersValues = vue.reactive(props.customFilters.reduce((acc, filter) => {
acc[filter.id] = filter.value;
return acc;
}, {}));
const init = async () => {
isLoading.value = true;
tableRows.value = await getRows(props.rows, props.config.showIndices || false, props.asyncRows);
filters.sort = initializeSortQueries(tableColumns.value);
handleFilters(filters.pagination);
isLoading.value = false;
};
const handleFilters = (paginator, search, sortColumn) => {
filters.search = search ?? "";
if (sortColumn)
filters.sort = updateSortQueries(filters.sort, sortColumn);
const _filteredRows = filterRows(tableRows.value, filters.search);
filteredRows.value = sortRows(_filteredRows, filters.sort);
if (filters.pagination.enabled) {
filters.pagination = calculatePageRange(paginator, totalFilteredRows.value, paginationPages.value);
activeRows.value = getActiveRows(filteredRows.value, filters.pagination);
}
else {
activeRows.value = filteredRows.value;
}
};
vue.watch(customFiltersValues, () => {
if (props.config.showSubmitButton === false) {
emit("customFilter", customFiltersValues);
}
}, {
immediate: true,
deep: true
});
vue.watch(() => props.rows, () => init(), { deep: true, immediate: true });
vue.onMounted(() => init());
const renderSearchbar = () => {
if (props.config.showSearchField !== false) {
return vue.h(vue$1.IonCol, { size: '4' }, [
vue.h(vue$1.IonSearchbar, {
placeholder: 'search here...',
class: 'box ion-no-padding',
value: filters.search,
onIonInput: (e) => handleFilters({ ...filters.pagination, page: 1 }, e.target.value),
})
]);
}
return null;
};
const renderSelectFilter = (filter) => vue.h(vue$1.IonCol, { size: `${filter.gridSize}` || '3' }, vue.h(SelectInput, {
options: filter.options,
placeholder: filter.label || filter.placeholder || 'Select Item',
value: filter.value,
multiple: filter.multiple,
onSelect: (v) => {
if (typeof filter.onUpdate === "function")
filter.onUpdate(v);
customFiltersValues[filter.id] = v;
}
}));
const renderDateRangeFilter = (filter) => vue.h(vue$1.IonCol, { size: `${filter.gridSize}` || '6' }, vue.h(DateRangePicker, {
range: (vue.computed(() => filter.value || { startDate: "", endDate: "" })).value,
onRangeChange: async (newRange) => {
if (typeof filter.onUpdate === "function")
filter.onUpdate(newRange);
customFiltersValues[filter.id] = newRange;
}
}));
const renderDefaultFilter = (filter) => vue.h(vue$1.IonCol, { size: '4' }, vue.h(vue$1.IonInput, {
class: 'box',
type: filter.type,
placeholder: filter.placeholder,
value: (vue.computed(() => filter.value || "")).value,
onIonInput: async (e) => {
const value = e.target.value;
if (typeof filter.onUpdate === "function")
filter.onUpdate(value);
customFiltersValues[filter.id] = value;
}
}));
const renderCustomFilters = () => {
return props.customFilters.map(filter => {
if (filter.slotName && typeof slots[filter.slotName] === "function") {
return vue.h(vue$1.IonCol, { size: `${filter.gridSize || '3'}` }, slots[filter.slotName]({ filter }));
}
if (filter.type === 'dateRange')
return renderDateRangeFilter(filter);
if (filter.type === 'select')
return renderSelectFilter(filter);
return renderDefaultFilter(filter);
});
};
const renderSubmitButton = () => {
if (props.customFilters.length > 0 && props.config.showSubmitButton !== false) {
return vue.h(vue$1.IonCol, { size: '2' }, [
vue.h(vue$1.IonButton, { color: "primary", class: "ion-no-margin", onClick: () => emit("customFilter", customFiltersValues) }, 'Submit')
]);
}
return null;
};
const renderActionsButtons = () => {
return props.actionsButtons.map(btn => vue.h(vue$1.IonButton, {
class: 'ion-float-right',
color: btn.color || 'primary',
size: btn.size ?? "default",
onClick: () => btn.action(activeRows.value, tableRows.value, filters, tableColumns.value)
}, btn.icon
? vue.h(vue$1.IonIcon, { icon: btn.icon })
: btn.label));
};
const renderFilterSection = () => {
return showFilterSection.value && vue.h(vue$1.IonGrid, { style: { width: '100%', fontWeight: 500 } }, vue.h(vue$1.IonRow, [
vue.h(vue$1.IonCol, { size: '7' }, vue.h(vue$1.IonRow, [
renderSearchbar(),
...renderCustomFilters(),
renderSubmitButton(),
])),
vue.h(vue$1.IonCol, { size: '5', class: "ion-padding-end" }, renderActionsButtons())
]));
};
const renderPagination = () => {
return filters.pagination.enabled && filters.pagination.totalPages > 1 && vue.h(vue$1.IonGrid, { style: { width: '100%', textAlign: 'left', color: 'black' }, class: 'ion-padding' }, vue.h(vue$1.IonRow, [
vue.h(vue$1.IonCol, { size: '4' }, renderPaginationControls()),
vue.h(vue$1.IonCol, { size: '5', class: "text-center" }, [
renderGoToPageInput(),
renderItemsPerPageSelect()
]),
vue.h(vue$1.IonCol, { size: '3' }, renderPaginationInfo())
]));
};
const renderPaginationControls = () => {
const { page, start, end, totalPages } = filters.pagination;
const handleClick = (page) => {
return handleFilters({ ...filters.pagination, page });
};
const controls = [
renderPageControlButton({
icon: icons.caretBack,
disabled: page === start,
onClick: () => handleClick(page - 1)
}),
];
if (start > 3) {
controls.push(renderPageControlButton({ label: '1', onClick: () => handleClick(1) }));
controls.push(renderPageControlButton({ label: '...', disabled: true }));
}
paginationPages.value.forEach(label => {
controls.push(renderPageControlButton({ label, onClick: () => handleClick(label) }));
});
if (end < totalPages - 2) {
controls.push(renderPageControlButton({ label: '...', disabled: true }));
controls.push(renderPageControlButton({ label: totalPages, onClick: () => handleClick(totalPages) }));
}
controls.push(renderPageControlButton({
icon: icons.caretForward,
disabled: page === end || isEmpty(filteredRows.value),
onClick: () => handleClick(page + 1)
}));
return controls;
};
const renderPageControlButton = ({ disabled, label, icon, onClick }) => {
return vue.h(vue$1.IonButton, {
onClick,
disabled,
size: 'small',
color: filters.pagination.page === label ? 'primary' : 'light',
}, icon ? vue.h(vue$1.IonIcon, { icon }) : label || "Button");
};
const renderGoToPageInput = () => {
return vue.h(vue$1.IonItem, { class: "box go-to-input ion-hide-xl-down", lines: "none" }, [
vue.h(vue$1.IonLabel, { class: 'ion-margin-end' }, "Go to page"),
vue.h(vue$1.IonInput, {
type: "number",
min: 1,
max: filters.pagination.totalPages,
value: filters.pagination.page,
style: { paddingRight: '15px' },
debounce: 500,
onIonChange: (e) => {
const page = e.target.value;
if (page > 0 && page <= filters.pagination.totalPages) {
handleFilters({ ...filters.pagination, page });
}
}
}),
]);
};
const renderItemsPerPageSelect = () => {
return vue.h(vue$1.IonItem, { class: "box per-page-input", lines: "none" }, [
vue.h(vue$1.IonLabel, "Items per page"),
vue.h(vue$1.IonSelect, {
value: filters.pagination.pageSize,
onIonChange: (e) => handleFilters({
...filters.pagination,
pageSize: e.target.value,
page: 1
}),
}, [
...filters.pagination.pageSizeOptions.map(value => vue.h(vue$1.IonSelectOption, { value, key: value }, value)),
vue.h(vue$1.IonSelectOption, { value: totalFilteredRows.value }, "All")
]),
]);
};
const renderPaginationInfo = () => {
return vue.h(vue$1.IonCol, { size: '4', class: "pagination-info" }, (vue.computed(() => {
return buildPaginationInfo(filters.pagination, totalFilteredRows.value);
})).value);
};
const renderTableHeader = () => vue.h("thead", { class: props.color || "" }, vue.h("tr", [
...tableColumns.value.map(column => renderTableHeaderCell(column)),
!isEmpty(props.rowActionsButtons) && vue.h('th', 'Actions')
]));
const renderSortIcon = (column) => {
const style = { marginRight: "5px", float: "right", cursor: 'pointer' };
const icon = vue.computed(() => {
const query = filters.sort.find(s => s.column.path === column.path);
return !query ? icons.swapVertical : query.order == "asc" ? icons.arrowUp : icons.arrowDown;
});
return vue.h(vue$1.IonIcon, { icon: icon.value, style });
};
const renderTableHeaderCell = (column) => {
const style = { minWidth: /index/i.test(column.path) ? '80px' : '190px', ...column.thStyles };
const onClick = () => handleFilters(filters.pagination, filters.search, column);
return vue.h("th", { key: column.label, style, class: column.thClasses?.join(" "), onClick }, [
vue.h("span", column.label),
column.sortable !== false && renderSortIcon(column),
]);
};
const renderTableBody = () => {
return vue.h("tbody", { class: "table-body" }, isLoading.value || props.loading
? renderLoadingRows()
: isEmpty(filteredRows.value)
? renderNoDataRow()
: renderDataRows());
};
const renderLoadingRows = () => {
return range(0, 9).map(i => vue.h("tr", { key: i }, vue.h('td', { colspan: totalColumns.value }, vue.h(vue$1.IonSkeletonText, { animated: true, style: { width: '100%' } }))));
};
const renderNoDataRow = () => {
return vue.h('tr', vue.h('td', { colspan: totalColumns.value }, vue.h('div', { class: 'no-data-table' }, 'No data available')));
};
const handleRowClick = async (row, rowIndex) => {
const defaultActionBtn = props.rowActionsButtons.find(btn => btn.default);
if (defaultActionBtn)
await defaultActionBtn.action(row, rowIndex);
};
const renderDataRows = () => {
return activeRows.value.map((row, rowIndex) => vue.h('tr', { key: row, onClick: () => handleRowClick(row, rowIndex) }, [
...renderDataRowCells(row),
renderRowActionCells(row, rowIndex)
]));
};
const renderDataRowCells = (row) => {
return tableColumns.value.map((column, key) => {
const classes = ["data-cell", ...column.tdClasses ?? []].join(" ");
return vue.h('td', { key, class: classes, style: column.tdStyles }, renderCellContent(row, column));
});
};
const renderCellContent = (row, column) => {
let value = get(row, column.path);
if (typeof column.formatter === 'function' && value)
value = column.formatter(value, row);
if (isDrillable(column, value, row)) {
return vue.h('a', { onClick: () => emit("drilldown", { column, row }) }, renderCellValue(value));
}
else {
return renderCellValue(value);
}
};
const renderCellValue = (value) => {
return Array.isArray(value) ? value.length : value;
};
const renderRowActionCells = (row, rowIndex) => {
if (!isEmpty(props.rowActionsButtons)) {
return vue.h('td', props.rowActionsButtons.map(btn => {
const canShowBtn = typeof btn.condition === 'function' ? btn.condition(row) : true;
return canShowBtn ? renderRowActionButton(row, rowIndex, btn) : null;
}));
}
return null;
};
const renderRowActionButton = (row, rowIndex, btn) => {
return vue.h(vue$1.IonButton, {
key: btn.icon,
size: btn.size ?? 'small',
color: btn.color || 'primary',
onClick: () => btn.action(row, rowIndex)
}, btn.icon ? vue.h(vue$1.IonIcon, { icon: btn.icon }) : btn.label || "Button");
};
const renderTable = () => {
return vue.h("div", { class: "responsive-table ion-padding-horizontal" }, vue.h("table", { class: "table bordered-table striped-table" }, [
renderTableHeader(),
renderTableBody()
]));
};
return () => [
renderFilterSection(),
renderTable(),
renderPagination(),
];
}
});
// The Install function used by Vue to register the plugin
const VTable = {
install(app, options) {
app.config.globalProperties.$globalTableOptions = options;
app.provide("globalTableOptions", options);
app.component('DataTable', DataTable);
}
};
exports.DataTable = DataTable;
exports.VTable = VTable;
exports.buildPaginationInfo = buildPaginationInfo;
exports.calculatePageRange = calculatePageRange;
exports.filterRows = filterRows;
exports.getActiveRows = getActiveRows;
exports.getRows = getRows;
exports.initializeSortQueries = initializeSortQueries;
exports.isDrillable = isDrillable;
exports.sortRows = sortRows;
exports.updateSortQueries = updateSortQueries;
//# sourceMappingURL=index.js.map