246 lines
6.6 KiB
Vue
246 lines
6.6 KiB
Vue
<template>
|
|
<!-- NODE PROPS EDITOR -->
|
|
<fieldset
|
|
ref="mainMenuNodeEditor"
|
|
class="main-menu-node-editor-component container-fluid mb-3"
|
|
>
|
|
<!-- LEGEND -->
|
|
<legend>
|
|
<span class="fs-5">{{ __("Modification d'un noeud") }}</span>
|
|
<button
|
|
class="btn btn-sm btn-primary float-end mt-2"
|
|
:title="__('Fermer la modification')"
|
|
data-bs-toggle="tooltip"
|
|
@click.prevent="closeEditor"
|
|
>
|
|
<FontAwesomeIcon icon="fa fa-close" />
|
|
</button>
|
|
</legend>
|
|
<!-- MENU NAME -->
|
|
<div class="mb-3 row">
|
|
<label
|
|
for="title-node"
|
|
class="col-sm-2 col-form-label"
|
|
>
|
|
{{ __("Titre du noeud principal") }}
|
|
</label>
|
|
<div class="col-sm-10 p-2">
|
|
<WordCounter
|
|
id="title-node"
|
|
class="ck-word-count"
|
|
/>
|
|
<input
|
|
id="title-node"
|
|
type="text"
|
|
class="form-control"
|
|
:value="menuNode.title"
|
|
@blur="menuNode.title = ($event.target as HTMLInputElement).value"
|
|
>
|
|
<small class="form-text text-body-secondary">
|
|
{{ __('validation.between.string', {
|
|
attribute: "titre du noeud principal",
|
|
min: "3",
|
|
max: "255",
|
|
}) }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<!-- MENU PUBLISHED -->
|
|
<div class="mb-3 row">
|
|
<!-- LINK TARGET -->
|
|
<label
|
|
for="published-checkbox"
|
|
class="col-sm-2 col-form-label"
|
|
>
|
|
{{ __("Visibilité du noeud") }}
|
|
</label>
|
|
<div class="col p-2">
|
|
<div class="form-check form-switch py-0">
|
|
<input
|
|
name="published"
|
|
class="form-check-input pt-3"
|
|
type="checkbox"
|
|
role="switch"
|
|
id="published-checkbox"
|
|
:checked="menuNode.published"
|
|
@blur="menuNode.published = ($event.target as HTMLInputElement).checked"
|
|
>
|
|
</div>
|
|
<small class="form-text text-body-secondary">{{ __('Deux réponses possibles : oui ou non (maximum 8 liens publiés).') }}</small>
|
|
</div>
|
|
</div>
|
|
<!-- ROUTE NAME -->
|
|
<div
|
|
v-if="props.enum.value !== MenuNodeTypeEnum.link"
|
|
class="mb-3 row"
|
|
>
|
|
<label
|
|
for="type"
|
|
class="col-sm-2 col-form-label"
|
|
>
|
|
{{ __("Lien du noeud") }}
|
|
</label>
|
|
<div class="col p-2">
|
|
<div class="input-group">
|
|
<input
|
|
type="text"
|
|
class="form-control"
|
|
:value="getUrlFromRoute(String(menuNode.link.routeName))"
|
|
disabled
|
|
>
|
|
<a
|
|
class="btn btn-info"
|
|
target="_blank"
|
|
:href="getUrlFromRoute(String(menuNode.link.routeName))"
|
|
:title="__('Accéder à la page liée')"
|
|
data-bs-toggle="tooltip"
|
|
>
|
|
<FontAwesomeIcon icon="fa fa-arrow-up-right-from-square" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- URL -->
|
|
<div
|
|
v-else
|
|
class="mb-3 row"
|
|
>
|
|
<label
|
|
for="type"
|
|
class="col-sm-2 col-form-label"
|
|
>
|
|
{{ __("Url") }}
|
|
</label>
|
|
<div class="col p-2">
|
|
<div>
|
|
<WordCounter
|
|
id="node-url"
|
|
class="ck-word-count"
|
|
/>
|
|
<div class="input-group">
|
|
<input
|
|
ref="urlInput"
|
|
id="node-url"
|
|
type="text"
|
|
class="form-control"
|
|
:value="String(menuNode.link.url)"
|
|
@blur="saveUrl(($event.target as HTMLInputElement | null)!.value)"
|
|
>
|
|
<a
|
|
class="btn btn-info rounded-top-0"
|
|
target="_blank"
|
|
:href="String(menuNode.link.url)"
|
|
:title="__('Accéder à la page liée')"
|
|
data-bs-toggle="tooltip"
|
|
>
|
|
<FontAwesomeIcon icon="fa fa-arrow-up-right-from-square" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<small class="form-text text-body-secondary">
|
|
{{ __('Doît être une url valide.') }}
|
|
</small>
|
|
</div>
|
|
<small
|
|
v-if="!urlIsValid"
|
|
class="d-block text-danger"
|
|
>{{ __("L'url saisie n'est pas valide") }}</small>
|
|
</div>
|
|
</fieldset>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
|
import { __ } from "@modules/trans";
|
|
import { onMounted, ref, watch, type PropType } from "vue";
|
|
import route from "../../modules/route";
|
|
import type { MenuNodeInterface } from "../../types/models/MenuNode";
|
|
import { MenuNodeTypeEnum } from "../enums";
|
|
import { Tooltips } from "./../../modules/bsTooltips";
|
|
import MainMenuNodeDataEditor from "./MainMenuNodeDataEditor.vue";
|
|
import WordCounter from "./WordCounterComponent.vue";
|
|
|
|
defineOptions({
|
|
name: "MainMenuNodeEditor",
|
|
components: {MainMenuNodeDataEditor}
|
|
});
|
|
|
|
// * EMITS
|
|
const emits = defineEmits<{
|
|
closeEditor: [],
|
|
updatedNode: [menuNode: MenuNodeInterface],
|
|
}>();
|
|
|
|
// * PROPS
|
|
const props = defineProps({
|
|
menuNode: {
|
|
type: Object as PropType<MenuNodeInterface>,
|
|
required: true
|
|
},
|
|
enum: {
|
|
type: Object as PropType<Enum>,
|
|
required: true
|
|
}
|
|
});
|
|
|
|
// * REFS
|
|
const mainMenuNodeEditor = ref<HTMLInputElement|null>(null);
|
|
const urlInput = ref<HTMLInputElement|null>(null);
|
|
|
|
// * DATA
|
|
const menuNode = ref<MenuNodeInterface>(Object.assign({}, props.menuNode));
|
|
const urlIsValid = ref<boolean>(true);
|
|
const tooltips = ref<Tooltips|null>(null);
|
|
|
|
// * LIFECYCLE
|
|
onMounted(() => {
|
|
urlIsValid.value = isUrlValid(String(menuNode.value.link.url));
|
|
initTooltips();
|
|
});
|
|
|
|
// * WATCHERS
|
|
watch(menuNode, (newValue) => {
|
|
emits("updatedNode", newValue);
|
|
}, { deep: true });
|
|
|
|
// * METHODS
|
|
|
|
function saveUrl(newUrl: string): void {
|
|
urlIsValid.value = isUrlValid(newUrl);
|
|
menuNode.value.link.url = urlInput.value!.value;
|
|
}
|
|
|
|
function closeEditor(): void {
|
|
tooltips.value?.closeBootstrapTooltip();
|
|
emits("closeEditor");
|
|
}
|
|
|
|
function isUrlValid(url: string):boolean {
|
|
const regex = RegExp("(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$", "i");
|
|
return url.match(regex)?.[0] !== undefined;
|
|
}
|
|
|
|
function getUrlFromRoute(url: string) {
|
|
const routeUrl = route(url);
|
|
if (!routeUrl) {
|
|
throw new Error("Undefined route " + url);
|
|
}
|
|
return routeUrl;
|
|
}
|
|
|
|
/** Initialise all tooltips in the component */
|
|
function initTooltips(): void {
|
|
setTimeout(() => {
|
|
tooltips.value = Tooltips.make({
|
|
type: "dom",
|
|
elements: mainMenuNodeEditor.value!.querySelectorAll("[data-bs-toggle=\"tooltip\"]")
|
|
});
|
|
}, 500);
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.main-menu-node-editor-component {
|
|
max-height: 30rem;
|
|
}
|
|
</style>
|