mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
continue tabulator vue implementation
* add jsdoc function comments * add base props for component * add loop logic to add needed formatters * now vue component will be store in a list that will allow to render them and use Teleport Vue utils to add them inside the right table cell * retrieve previous cell component * create a utils/tabulator.js for some purposes like custom sort, custom mutating, etc... * start some custom format (Icons, Text) and add a wrapper to use in the component
This commit is contained in:
parent
20975be247
commit
01b04004ea
2 changed files with 247 additions and 37 deletions
|
|
@ -60,11 +60,107 @@ onMounted(() => {
|
|||
</template> -->
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, Teleport, computed } from "vue";
|
||||
import { ref, reactive, onMounted, Teleport, computed, onUnmounted } from "vue";
|
||||
import Icons from "@components/Widget/Icons.vue";
|
||||
import Text from "@components/Widget/Text.vue";
|
||||
import Fields from "@components/Form/Fields.vue";
|
||||
import Button from "@components/Widget/Button.vue";
|
||||
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
|
||||
import { TabulatorFull as Tabulator } from "tabulator-tables"; //import Tabulator library
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
import { addSorter } from "@utils/tabulator.js";
|
||||
|
||||
// TODO : ADD JSDOC COMPONENT
|
||||
|
||||
const customComponents = ["Icons", "Text", "Fields", "Button", "ButtonGroup"];
|
||||
|
||||
const props = defineProps({
|
||||
columns: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: [
|
||||
{ title: "Name", field: "name", width: 150 },
|
||||
{ title: "Icon", field: "icon", formatter: "icons" },
|
||||
],
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: [
|
||||
{ id: 1, name: "Oli Bob", icon: { iconName: "box", color: "amber" } },
|
||||
{
|
||||
id: 2,
|
||||
name: "Mary May",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Christine Lobowski",
|
||||
icon: { iconName: "box", color: "amber" },
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Brendon Philips",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Margret Marmajuke",
|
||||
icon: { iconName: "box", color: "amber" },
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Frank Harbours",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Jamie Newhart",
|
||||
icon: { iconName: "box", color: "amber" },
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Gemma Jane",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{ id: 9, name: "Emily Sykes", icon: { iconName: "box", color: "amber" } },
|
||||
{
|
||||
id: 10,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "James Newman",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
],
|
||||
},
|
||||
isPagination: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -73,7 +169,7 @@ const props = defineProps({
|
|||
paginationSize: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 1,
|
||||
default: 10,
|
||||
},
|
||||
paginationInitialPage: {
|
||||
type: Number,
|
||||
|
|
@ -90,32 +186,22 @@ const props = defineProps({
|
|||
const tableEl = ref(null); //reference to your table element
|
||||
|
||||
const table = reactive({
|
||||
test: true,
|
||||
instance: null,
|
||||
columns: [
|
||||
{ title: "Name", field: "name", width: 150 },
|
||||
{ title: "Icon", field: "icon", formatter: "icons" },
|
||||
],
|
||||
data: [
|
||||
{ id: 1, name: "test", icon: { iconName: "box", color: "amber" } },
|
||||
{
|
||||
id: 2,
|
||||
name: "test",
|
||||
icon: { iconName: "document", color: "blue" },
|
||||
},
|
||||
{ id: 3, name: "test", icon: { iconName: "box", color: "amber" } },
|
||||
{ id: 4, name: "test", icon: { iconName: "document", color: "blue" } },
|
||||
{ id: 5, name: "test", icon: { iconName: "box", color: "amber" } },
|
||||
{ id: 6, name: "test", icon: { iconName: "document", color: "blue" } },
|
||||
{ id: 7, name: "test", icon: { iconName: "box", color: "amber" } },
|
||||
],
|
||||
columns: props.columns,
|
||||
data: props.data,
|
||||
customComponents: [],
|
||||
options: computed(() => {
|
||||
const opts = {
|
||||
data: table.data, //link data to table
|
||||
reactiveData: true, //enable data reactivity
|
||||
columns: table.columns, //define table columns
|
||||
};
|
||||
|
||||
// columns formatting
|
||||
let columns = JSON.parse(JSON.stringify(table.columns));
|
||||
columns = addSortComponents(columns);
|
||||
opts.columns = columns;
|
||||
|
||||
if (props.isPagination) {
|
||||
opts.pagination = true;
|
||||
opts.paginationSize = props.paginationSize;
|
||||
|
|
@ -128,7 +214,17 @@ const table = reactive({
|
|||
}),
|
||||
});
|
||||
|
||||
function setCustomComponent(type, values, elDOM) {
|
||||
/**
|
||||
* @name addCustomComponent
|
||||
* @description Utils to add needed data when we have a custom component.
|
||||
* We will use the type to render the Vue component, the values to pass and the elDOM to teleport the component inside the right cell.
|
||||
* @example { type: "Icons", values: { iconName: "box", color: "amber" }, elDOM: HTMLElement }
|
||||
* @param {str} type - The type is the name of the component.
|
||||
* @param {object} values - The values are the props that we want to pass to the component.
|
||||
* @param {HTMLElement} elDOM - The elDOM is the element where we want to teleport the component.
|
||||
* @returns {void}
|
||||
*/
|
||||
function addCustomComponent(type, values, elDOM) {
|
||||
table.customComponents.push({
|
||||
type: type,
|
||||
values: values,
|
||||
|
|
@ -136,22 +232,51 @@ function setCustomComponent(type, values, elDOM) {
|
|||
});
|
||||
}
|
||||
|
||||
function addModules() {
|
||||
Tabulator.extendModule("format", "formatters", {
|
||||
icons: function (cell, formatterParams) {
|
||||
setCustomComponent("Icons", cell.getValue(), cell.getElement());
|
||||
/**
|
||||
* @name addComponentsFormats
|
||||
* @description Add all custom components on a list to later add them to each tabulator cell.
|
||||
* We are using the Tabulart.extendModule() that allow use to execute a custom function when we are matching a custom formatter.
|
||||
* We need to define on rows the formatter that we want to use to render the custom component.
|
||||
* @returns {void}
|
||||
*/
|
||||
function addComponentsFormats() {
|
||||
const formatOpts = {};
|
||||
for (let i = 0; i < customComponents.length; i++) {
|
||||
const module = customComponents[i];
|
||||
formatOpts[module.toLowerCase()] = function (cell, formatterParams) {
|
||||
addCustomComponent(module, cell.getValue(), cell.getElement());
|
||||
return "";
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
Tabulator.extendModule("format", "formatters", formatOpts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name addSortComponents
|
||||
* @description Check every columns and add a custom sort for some components, so this is link to customComponents list and previous formatters set.
|
||||
* @example For Icons, we will add a custom sorter that will check between iconNames.
|
||||
* @param {array} columns - The columns are the list of columns that we want to check.
|
||||
* @returns {array} - Return the columns with the custom sort added.
|
||||
*/
|
||||
function addSortComponents(columns) {
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
const column = columns[i];
|
||||
if (!("formatter" in column)) continue;
|
||||
const formatName = column.formatter.toLowerCase();
|
||||
|
||||
addSorter(column, formatName);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
addModules();
|
||||
//instantiate Tabulator when element is mounted
|
||||
addComponentsFormats();
|
||||
table.instance = new Tabulator(tableEl.value, table.options);
|
||||
table.instance.on("tableBuilt", () => {
|
||||
console.log("tableBuilt");
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
table.instance.destroy();
|
||||
table.instance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -160,16 +285,28 @@ onMounted(() => {
|
|||
href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<div ref="tableEl"></div>
|
||||
<template
|
||||
:key="table.customComponents"
|
||||
v-for="component in table.customComponents"
|
||||
v-for="comp in table.customComponents"
|
||||
>
|
||||
<Teleport :to="component.elDOM">
|
||||
<Teleport :to="comp.elDOM">
|
||||
<Icons
|
||||
v-if="component.type === 'Icons'"
|
||||
v-bind="{ ...component.values }"
|
||||
v-if="useEqualStr(comp.type, 'Icons')"
|
||||
v-bind="{ ...comp.values }"
|
||||
/>
|
||||
<Text v-if="useEqualStr(comp.type, 'Text')" v-bind="{ ...comp.values }" />
|
||||
<Fields
|
||||
v-if="useEqualStr(comp.type, 'Fields')"
|
||||
v-bind="{ ...comp.values }"
|
||||
/>
|
||||
<Button
|
||||
v-if="useEqualStr(comp.type, 'Button')"
|
||||
v-bind="{ ...comp.values }"
|
||||
/>
|
||||
<ButtonGroup
|
||||
v-if="useEqualStr(comp.type, 'ButtonGroup')"
|
||||
v-bind="{ ...comp.values }"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
|
|
|||
73
src/ui/client/dashboard/utils/tabulator.js
Normal file
73
src/ui/client/dashboard/utils/tabulator.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @name utils/tabulator.js
|
||||
* @description This file contains utils to work with the tabulator library and Vue instance.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name addSorter
|
||||
* @description This is a wrapper that will execute every sorter function in order to add a new sorter to the tabulator library.
|
||||
* @example { title: "Icon", field: "icon", formatter: "icons" }
|
||||
* @param {object} column - The column object to update in case we have the right format.
|
||||
* @param {formatName} column - Check if the current column format is the right one.
|
||||
* @returns {void}
|
||||
*/
|
||||
function addSorter(column, formatName) {
|
||||
sortIcons(column, formatName);
|
||||
sortText(column, formatName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name sortIcons
|
||||
* @description Add sorter for Icons components in the tabulator.
|
||||
* @example { title: "Icon", field: "icon", formatter: "icons" }
|
||||
* @param {object} column - The column object to update in case we have the right format.
|
||||
* @param {formatName} column - Check if the current column format is the right one.
|
||||
* @returns {void}
|
||||
*/
|
||||
function sortIcons(column, formatName) {
|
||||
if (formatName !== "icons") return;
|
||||
column.sorter = (a, b, aRow, bRow, column, dir, params) => {
|
||||
const aName = a.iconName;
|
||||
const bName = b.iconName;
|
||||
let alignEmptyValues = params.alignEmptyValues;
|
||||
let emptyAlign = 0;
|
||||
let locale;
|
||||
|
||||
if (aName && bName) {
|
||||
locale =
|
||||
typeof params.locale == "boolean" ? this.langLocale() : params.locale;
|
||||
|
||||
return String(aName)
|
||||
.toLowerCase()
|
||||
.localeCompare(String(bName).toLowerCase(), locale);
|
||||
}
|
||||
|
||||
if (!aName) emptyAlign = !bName ? 0 : -1;
|
||||
if (!bName) emptyAlign = 1;
|
||||
|
||||
//fix empty values in position
|
||||
if (
|
||||
(alignEmptyValues === "top" && dir === "desc") ||
|
||||
(alignEmptyValues === "bottom" && dir === "asc")
|
||||
) {
|
||||
emptyAlign *= -1;
|
||||
}
|
||||
|
||||
return emptyAlign;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name sortText
|
||||
* @description Add sorter for Text components in the tabulator. Under the hood, this will use the default tabulator sorter for strings.
|
||||
* @example { title: "Icon", field: "icon", formatter: "icons" }
|
||||
* @param {object} column - The column object to update in case we have the right format.
|
||||
* @param {formatName} column - Check if the current column format is the right one.
|
||||
* @returns {void}
|
||||
*/
|
||||
function sortText(column, formatName) {
|
||||
if (formatName !== "text") return;
|
||||
column.sorter = "string";
|
||||
}
|
||||
|
||||
export { addSorter, sortIcons, sortText };
|
||||
Loading…
Reference in a new issue