306 lines
8.8 KiB
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>
|