ldc-loue/resources/ts/components/bo/ModelLinkComponent.vue

287 lines
7.1 KiB
Vue
Raw Permalink Normal View History

2022-07-18 08:24:42 +00:00
<template>
<div class="ModelLink form-control">
<VueSelect
2022-09-19 09:10:04 +00:00
:placeholder="intPlaceholder"
:loading="loading"
v-model="intValue"
2022-07-18 08:24:42 +00:00
:clearable="true"
label="label"
2022-09-19 09:10:04 +00:00
:options="data"
@search="searchAjax"
:disabled="intReadonly || intDisabled"
2022-07-18 08:24:42 +00:00
:filterable="true"
:searchable="true"
>
2022-09-19 09:10:04 +00:00
<template #option="{ label }: { label: string }">
2022-07-18 08:24:42 +00:00
{{
2022-09-19 09:10:04 +00:00
label.length >= intMaxLength ? label.substring(0, intMaxLength) + ".." : label
2022-07-18 08:24:42 +00:00
}}
</template>
2022-09-19 09:10:04 +00:00
<template
#no-options="{ search, searching }: { search: string, searching: boolean }"
>
2022-07-18 08:24:42 +00:00
<template v-if="searching">
{{ __("Aucun résultat pour") }}
<em>{{ search }}</em> .
</template>
2022-09-19 09:10:04 +00:00
<em
v-else
style="opacity: 0.5"
>
{{ __("Chercher un lien du site") }}
</em>
2022-07-18 08:24:42 +00:00
</template>
2022-09-19 09:10:04 +00:00
<template #list-footer>
<li
class="pagination"
v-if="data.length"
>
2022-07-18 08:24:42 +00:00
<button
2022-09-19 09:10:04 +00:00
@click.prevent="page -= 1"
:disabled="!hasPrevPage"
2022-07-18 08:24:42 +00:00
class="btn btn-sm btn-primary mt-2 mb-2 ms-2 me-2"
>
{{ __("précédent") }}
</button>
<button
2022-09-19 09:10:04 +00:00
@click.prevent="page += 1"
:disabled="!hasNextPage"
2022-07-18 08:24:42 +00:00
class="btn btn-sm btn-primary mt-2 mb-2"
>
{{ __("suivant") }}
</button>
</li>
</template>
</VueSelect>
2022-09-19 09:10:04 +00:00
<input
v-if="isJson"
type="hidden"
:name="String(name)"
:value="intValue?.value"
>
2022-07-18 08:24:42 +00:00
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import VueSelect from "vue-select";
import trans from "../../modules/trans";
import route from "../../modules/route";
import axios from "axios";
type SelectModel = {
class: string;
label: string;
value: string;
};
export default defineComponent({
mixins: [trans, route],
components: {
VueSelect,
},
2022-09-19 09:10:04 +00:00
emits: ["input"],
2022-07-18 08:24:42 +00:00
beforeMount() {
if (!this.$attrs.json) {
throw new Error("this component requires json");
}
},
mounted() {
2022-09-19 09:10:04 +00:00
const json = String(this.$attrs.json ?? "{}");
const data = JSON.parse(json);
2022-07-18 08:24:42 +00:00
if (Object.keys(data).length) {
2022-09-19 09:10:04 +00:00
this.isJson = true;
this.name = data.name;
2022-07-18 08:24:42 +00:00
}
2022-09-19 09:10:04 +00:00
this.intDisabled = this.disabled ? this.disabled : data.disabled ? true : false;
this.intReadonly = this.readonly ? this.readonly : data.readonly ? true : false;
this.intPlaceholder = this.placeholder ? this.placeholder : data.placeholder;
this.intMaxLength = this.maxLength ? this.maxLength : data.maxLength;
2022-07-18 08:24:42 +00:00
this.parseValue(this.value ? this.value : data.value);
2022-09-19 09:10:04 +00:00
this.searchAjax();
2022-07-18 08:24:42 +00:00
},
props: {
disabled: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: "",
},
value: {
type: String,
default: "",
},
maxLength: {
type: Number,
default: 35,
},
},
data(): {
2022-09-19 09:10:04 +00:00
isJson: boolean;
name: string | null;
intDisabled: boolean;
intReadonly: boolean;
intPlaceholder: string;
intMaxLength: number;
intValue: SelectModel | null;
loading: boolean;
searchText: string;
data: SelectModel[];
page: number;
perPage: number;
hasNextPage: boolean;
hasPrevPage: boolean;
2022-07-18 08:24:42 +00:00
} {
return {
2022-09-19 09:10:04 +00:00
isJson: false,
name: null,
intDisabled: false,
intReadonly: false,
intPlaceholder: "",
intValue: null,
loading: false,
searchText: "",
data: [],
page: 1,
perPage: 15,
hasNextPage: true,
hasPrevPage: false,
intMaxLength: 65,
2022-07-18 08:24:42 +00:00
};
},
watch: {
2022-09-19 09:10:04 +00:00
page() {
if (this.page < 1) {
this.page = 1;
2022-07-18 08:24:42 +00:00
}
2022-09-19 09:10:04 +00:00
if (this.page > 1) {
this.hasPrevPage = true;
2022-07-18 08:24:42 +00:00
} else {
2022-09-19 09:10:04 +00:00
this.hasPrevPage = false;
2022-07-18 08:24:42 +00:00
}
2022-09-19 09:10:04 +00:00
this.searchAjax();
2022-07-18 08:24:42 +00:00
},
2022-09-19 09:10:04 +00:00
data() {
if (this.data.length == this.perPage) {
this.hasNextPage = true;
2022-07-18 08:24:42 +00:00
} else {
2022-09-19 09:10:04 +00:00
this.hasNextPage = false;
2022-07-18 08:24:42 +00:00
}
},
value() {
this.parseValue(this.value);
},
2022-09-19 09:10:04 +00:00
intValue() {
this.$emit("input", this.intValue ? this.intValue.value : "");
2022-07-18 08:24:42 +00:00
},
},
methods: {
2022-09-19 09:10:04 +00:00
searchAjax(search = null) {
2022-07-18 08:24:42 +00:00
if (search !== false && search !== null) {
2022-09-19 09:10:04 +00:00
this.searchText = search;
2022-07-18 08:24:42 +00:00
}
2022-09-19 09:10:04 +00:00
if (!this.searchText) {
2022-07-18 08:24:42 +00:00
return;
}
let routeUrl = route.methods.route("bo.ranges.search-uri");
if (!routeUrl) {
2022-09-19 09:10:04 +00:00
throw new Error("undefined route bo.ranges.search-uri");
2022-07-18 08:24:42 +00:00
}
const url = new URL(routeUrl);
routeUrl = `${url.origin}${url.pathname}?`;
2022-09-19 09:10:04 +00:00
routeUrl += "page=" + encodeURIComponent(this.page);
routeUrl += "&search=" + encodeURIComponent(this.searchText);
this.loading = true;
2022-07-18 08:24:42 +00:00
axios
.get(routeUrl)
.then((response) => {
this.parseResponse(response.data.data);
})
.catch((error) => {
console.error(error);
})
.then(() => {
2022-09-19 09:10:04 +00:00
this.loading = false;
2022-07-18 08:24:42 +00:00
});
},
parseValue(value: string | null) {
if (!value) {
2022-09-19 09:10:04 +00:00
this.intValue = null;
2022-07-18 08:24:42 +00:00
return;
}
let routeUrl = route.methods.route("bo.ranges.model-title");
if (!routeUrl) {
2022-09-19 09:10:04 +00:00
throw new Error("undefined route bo.ranges.model-title");
2022-07-18 08:24:42 +00:00
}
const url = new URL(routeUrl),
2022-09-19 09:10:04 +00:00
model = value.replace(/^#/, "").replace(/#$/, "").split("#");
2022-07-18 08:24:42 +00:00
routeUrl = `${url.origin}${url.pathname}?`;
routeUrl += "model=" + encodeURIComponent(model[0]);
routeUrl += "&id=" + encodeURIComponent(model[1]);
axios.get(routeUrl).then((response) => {
let label = String(response.data as string);
label =
2022-09-19 09:10:04 +00:00
label.length >= this.intMaxLength
? label.substring(0, this.intMaxLength) + ".."
: label;
2022-07-18 08:24:42 +00:00
if (label) {
2022-09-19 09:10:04 +00:00
this.intValue = this.parseResource({
2022-07-18 08:24:42 +00:00
class: model[0],
label: label,
value: model[1],
});
} else {
console.error("empty data response");
}
});
},
parseResource(model: SelectModel): SelectModel {
let label = model.label;
switch (model.class) {
case "App\\Models\\Recipe":
label = `${this.__("models.classes.recipes")} - ${model.label}`;
break;
case "App\\Models\\Breeder":
label = `${this.__("models.classes.breeders")} - ${model.label}`;
break;
}
return {
label: label,
class: model.class,
value: `#${model.class}#${model.value}#`,
};
},
parseResponse(data: SelectModel[]) {
const out: SelectModel[] = [];
for (const model of data) {
out.push(this.parseResource(model));
}
2022-09-19 09:10:04 +00:00
// pass searchText if is valid url and nothing else is found
2022-07-18 08:24:42 +00:00
if (out.length) {
2022-09-19 09:10:04 +00:00
this.data = out;
2022-07-18 08:24:42 +00:00
}
},
},
});
</script>
<style lang="scss">
@import "../../../../node_modules/vue-select/dist/vue-select.css";
.ModelLink {
padding: 0 !important;
2022-09-19 09:10:04 +00:00
2022-07-18 08:24:42 +00:00
.vs__dropdown-toggle {
border: 0 !important;
}
}
</style>