ldc-volena/resources/ts/bo/components/ListItemComponent.vue

306 lines
8.8 KiB
Vue

<template>
<div
:class="`list-item-component list-item-${inputParameters.name}`"
ref="listItem"
>
<table
v-if="itemParameters.list.length > 0"
class="table text-center table-sm table-hover table-bordered m-0"
ref="tableElement"
>
<thead>
<tr>
<th
v-for="(column, columnIndex) of itemParameters.columns"
:key="columnIndex"
scope="col"
>
{{ column[1] }}
</th>
<th
scope="col"
v-if="buttonsDisplayParameters.remove"
class="table-action"
>
<!-- Laisser vide -->
</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr
v-for="(item, itemIndex) of itemParameters.list"
:key="itemIndex"
>
<td
class="align-top"
v-for="(column, columnIndex) of itemParameters.columns"
:key="columnIndex"
>
<div
v-if="itemParameters.type[columnIndex] == 'boolean'"
class="form-check form-switch d-flex justify-content-center align-items-center p-0"
>
<input
class="form-check-input m-0"
type="checkbox"
role="switch"
:name="`${inputParameters.name}[${String(itemIndex)}][${column[0]}]`"
:checked="Boolean(item[column[0] as keyof typeof item])"
>
</div>
<div
v-else-if="itemParameters.type[columnIndex] == 'wysiwyg'"
:class="(getErrorMessage(itemIndex, column) !== null) ? 'is-invalid' : ''"
>
<CkEditorComponent
:name="`${inputParameters.name}[${String(itemIndex)}][${column[0]}]`"
:placeholder="inputParameters.placeholder[columnIndex]"
:dbtext="String(item[column[0] as keyof typeof item] ?? '')"
:required="true"
:errors="allErrors"
:editor-config="wysiwygConfig"
/>
</div>
<div
v-else-if="itemParameters.type[columnIndex] == 'picture'"
:class="(getErrorMessage(itemIndex, column) !== null) ? 'is-invalid' : ''"
>
<ImageInputComponent
:id="'picture-input-' + id + itemIndex"
:required="true"
:show-labels="true"
:name="`${inputParameters.name}[${String(itemIndex)}][${column[0]}]`"
:helper="trans.methods.__('crud.minicrud.dimensions_must_be', {
widthpx: (imageSizes[0] ?? String(500)) + 'px',
heightpx: (imageSizes[1] ?? String(500)) + 'px',
})"
:width="imageSizes[0] ?? 500"
:height="imageSizes[1] ?? 500"
:value="item[column[0] as keyof typeof item] ? String(item[column[0] as keyof typeof item]) : undefined"
:preview="false"
:browse-event="false"
/>
</div>
<input
v-else
:class="['form-control form-control-sm', (getErrorMessage(itemIndex, column) !== null) ? 'is-invalid' : '']"
:name="`${inputParameters.name}[${String(itemIndex)}][${column[0]}]`"
:type="itemParameters.type[columnIndex]"
v-model="item[column[0] as keyof typeof item]"
:placeholder="inputParameters.placeholder[columnIndex]"
:min="itemParameters.type[columnIndex] == 'number' ? '0' : undefined"
>
<small class="text-danger m-0">
{{ getErrorMessage(itemIndex, column) }}
</small>
</td>
<td
v-if="buttonsDisplayParameters.remove"
class="align-bottom"
>
<button
@click.prevent="removeLine(itemIndex)"
class="btn btn-sm btn-danger"
:title="trans.methods.__('Supprimer la ligne')"
data-bs-toggle="tooltip"
>
<i class="fa-solid fa-trash" />
</button>
</td>
</tr>
</tbody>
</table>
<div v-else>
<p>{{ trans.methods.__("Aucun élément renseigné(s).") }}</p>
</div>
<div
v-if="buttonsDisplayParameters.add"
class="text-center mt-1"
>
<button
@click.prevent="addLine"
class="btn btn-sm btn-primary"
type="button"
:title="trans.methods.__('Ajouter une ligne')"
data-bs-toggle="tooltip"
>
<i class="fa-solid fa-plus" />
</button>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, defineOptions, onMounted, reactive, ref, useAttrs } from "vue";
import { Tooltips } from "./../../modules/bsTooltips";
import parseLaravelErrorMessages from "./../../modules/parseLaravelErrorMessages";
import trans from "./../../modules/trans";
import CkEditorComponent from "./CkEditorComponent.vue";
import ImageInputComponent from "./ImageInputComponent.vue";
defineOptions({
name: "ListItemComponent"
});
// * ATTRIBUTES
const attrs = useAttrs();
// * REFS
const listItem = ref<HTMLDivElement|null>(null);
const tableElement = ref<HTMLTableElement|null>(null);
// * DATA
const tooltips = ref<Tooltips | null>(null);
const allErrors = ref<LaravelValidationErrors>({});
const wysiwygConfig = ref<string>();
const id = ref<string>();
/** Input parameters. */
const inputParameters = reactive<{
name: string,
placeholder: Array<string>,
}>({
name: "",
placeholder: [""],
});
/** Item parameters. */
const itemParameters = reactive<{
list: Array<Object>,
columns: Array<string[]>,
limits: Array<number>,
type: Array<string>,
}>({
list: [{}],
columns: [[""]],
limits: [0, 0],
type: [""],
});
/** Image Sizes. */
let imageSizes = [] as Array<number|null>;
/** Buttons parameters. */
const buttonsDisplayParameters = reactive<{
add: boolean,
remove: boolean,
}>({
add: true,
remove: true,
});
// * COMPUTED
const isUsedWithProps = computed<boolean>(() => attrs.json === undefined);
// * LIFECYCLE
onMounted(() => {
const json = String(attrs.json ?? "{}"),
data = JSON.parse(json);
if (!isUsedWithProps.value) {
/** Input parameters. */
inputParameters.name = data.inputName;
inputParameters.placeholder = data.inputPlaceholder;
/** Item parameters. */
itemParameters.list = data.itemList;
itemParameters.columns = data.itemColumns;
itemParameters.limits = data.itemLimit;
itemParameters.type = data.itemType;
imageSizes = data.imageSizes;
/** Global parameters */
allErrors.value = data.errors;
id.value = data.id ?? "";
/** Ckeditor specific parameter */
wysiwygConfig.value = String(data.wysiwygConfig);
}
setDefaultLines();
checkLengthList();
initTooltips();
});
// * METHODS
/**
* Set default line(s)
* according to the minimum limit defined.
*/
function setDefaultLines(): void {
if (itemParameters.list.length < 1) {
for (let index = 0; index < itemParameters.limits[0]; index++) {
addLine();
}
}
}
/**
* Add a new line to the <table>,
* add a new element to the array,
* show remove line button.
*/
function addLine(): void {
itemParameters.list.push({});
if (buttonsDisplayParameters.remove == false) {
buttonsDisplayParameters.remove = true;
}
checkLengthList();
tooltips.value?.closeBootstrapTooltip();
initTooltips();
}
/**
* Remove a specific line from the <table>,
* remove a specific element to the array,
* show adding line button.
*/
function removeLine(itemIndex: number): void {
itemParameters.list.splice(itemIndex, 1);
if (buttonsDisplayParameters.add == false) {
buttonsDisplayParameters.add = true;
}
checkLengthList();
tooltips.value?.closeBootstrapTooltip();
initTooltips();
}
/**
* Check the length of the list,
* update variables accordingly.
*/
function checkLengthList(): void {
/** Length minimum */
if (itemParameters.list.length <= itemParameters.limits[0]) {
buttonsDisplayParameters.remove = false;
}
/** Length maximum */
if (itemParameters.list.length >= itemParameters.limits[1]) {
buttonsDisplayParameters.add = false;
}
}
/** Return error message or null. */
function getErrorMessage(itemIndex: number, column: string[]): string|null {
return parseLaravelErrorMessages.methods.parseValidationInput(
`${inputParameters.name}.${String(itemIndex)}.${column[0]}`,
allErrors.value
);
}
/** Initialise all tooltips in the component. */
function initTooltips(): void {
setTimeout(() => {
tooltips.value = Tooltips.make({
type: "dom",
elements: listItem.value!.querySelectorAll("[data-bs-toggle=\"tooltip\"]")
});
}, 500);
}
</script>
<style lang="scss">
.list-item-component .table-action {
width: 2rem;
}
.list-item-component .table {
table-layout: fixed;
}
</style>