@saooti/octopus-sdk 41.0.13-SNAPSHOT → 41.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +3 -1
  2. package/plateform.conf +1 -1
  3. package/src/App.vue +3 -7
  4. package/src/api/classicApi.ts +1 -1
  5. package/src/components/composable/player/usePlayerLive.ts +2 -2
  6. package/src/components/composable/radio/usefetchRadioData.ts +29 -12
  7. package/src/components/display/categories/CategoryChooser.vue +4 -0
  8. package/src/components/display/comments/CommentList.vue +1 -1
  9. package/src/components/display/emission/EmissionPresentationItem.vue +14 -6
  10. package/src/components/display/filter/DateFilter.vue +15 -2
  11. package/src/components/display/live/RadioCurrently.vue +2 -5
  12. package/src/components/display/podcasts/PodcastPlayButton.vue +4 -1
  13. package/src/components/display/rubriques/RubriqueChooser.vue +24 -2
  14. package/src/components/display/rubriques/RubriqueList.vue +18 -0
  15. package/src/components/display/sharing/PlayerParameters.vue +0 -8
  16. package/src/components/display/sharing/SharePlayer.vue +0 -5
  17. package/src/components/display/sharing/SubscribeButtons.vue +4 -2
  18. package/src/components/form/ClassicInputText.vue +3 -0
  19. package/src/components/form/ClassicMultiselect.vue +35 -7
  20. package/src/components/misc/ClassicAccordion.vue +4 -4
  21. package/src/components/misc/ClassicSpinner.vue +1 -1
  22. package/src/components/misc/HomeDropdown.vue +3 -110
  23. package/src/components/misc/MobileMenu.vue +59 -64
  24. package/src/components/misc/TopBar.vue +4 -11
  25. package/src/components/misc/TopBarMainContent.vue +0 -2
  26. package/src/components/misc/UserButtonContent.vue +159 -0
  27. package/src/components/misc/player/elements/PlayerImage.vue +0 -1
  28. package/src/components/misc/player/elements/PlayerTitle.vue +3 -3
  29. package/src/components/misc/player/radio/RadioHistory.vue +3 -2
  30. package/src/components/misc/player/video/PlayerVideo.vue +2 -2
  31. package/src/components/pages/HomePage.vue +1 -1
  32. package/src/components/pages/PageLogout.vue +1 -6
  33. package/src/components/pages/PodcastPage.vue +0 -1
  34. package/src/components/pages/VideoPage.vue +5 -2
  35. package/src/locale/de.ts +6 -5
  36. package/src/locale/en.ts +6 -5
  37. package/src/locale/es.ts +6 -5
  38. package/src/locale/fr.ts +6 -5
  39. package/src/locale/it.ts +6 -5
  40. package/src/locale/sl.ts +6 -5
  41. package/src/stores/PlayerStore.ts +6 -1
  42. package/src/stores/class/conference/conference.ts +2 -0
  43. package/src/stores/class/general/player.ts +2 -2
  44. package/src/style/_variables.scss +6 -0
  45. package/src/style/general.scss +18 -1
  46. package/src/helper/radio/radioHelper.ts +0 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "41.0.13-SNAPSHOT",
3
+ "version": "41.0.13",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -8,6 +8,7 @@
8
8
  "serve": "vite preview",
9
9
  "build": "vite build",
10
10
  "dev": "vite",
11
+ "bundle": "vite-bundle-visualizer",
11
12
  "proxy_authentifié": "node proxy.ts",
12
13
  "proxy_non_authentifié": "node proxy.ts false",
13
14
  "lint": "eslint --fix src",
@@ -53,6 +54,7 @@
53
54
  "video.js": "^8.23.3",
54
55
  "videojs-quality-selector-hls": "^1.1.1",
55
56
  "vite": "^6.3.5",
57
+ "vite-bundle-visualizer": "^1.2.1",
56
58
  "vue": "^3.5.16",
57
59
  "vue-i18n": "^11.1.5",
58
60
  "vue-material-design-icons": "^5.3.1",
package/plateform.conf CHANGED
@@ -1 +1 @@
1
- dev2.saooti.org
1
+ preprod.saooti.org
package/src/App.vue CHANGED
@@ -8,16 +8,14 @@
8
8
  <router-view />
9
9
  <PlayerComponent />
10
10
  </main>
11
- <ClassicLazy :min-height="123">
12
- <FooterOctopus />
13
- </ClassicLazy>
11
+ <FooterOctopus />
14
12
  </template>
15
13
  </div>
16
14
  </template>
17
15
  <script setup lang="ts">
18
16
  import TopBar from "@/components/misc/TopBar.vue";
17
+ import FooterOctopus from "@/components/misc/FooterSection.vue";
19
18
  import PlayerComponent from "@/components/misc/player/PlayerComponent.vue";
20
- import ClassicLazy from "@/components/misc/ClassicLazy.vue";
21
19
  import {useInit} from "./components/composable/useInit";
22
20
  import {useMetaTitle} from "./components/composable/useMetaTitle";
23
21
  import {useOrganisationFilter} from "./components/composable/useOrganisationFilter";
@@ -25,9 +23,7 @@ import { useAuthStore } from "./stores/AuthStore";
25
23
  import { defineAsyncComponent, getCurrentInstance, onBeforeMount, ref, watch } from "vue";
26
24
  import { useRoute } from "vue-router";
27
25
  import { useI18n } from "vue-i18n";
28
- const FooterOctopus = defineAsyncComponent(
29
- () => import("@/components/misc/FooterSection.vue"),
30
- );
26
+
31
27
  const CategoryFilter = defineAsyncComponent(
32
28
  () => import("@/components/display/categories/CategoryFilter.vue"),
33
29
  );
@@ -78,7 +78,7 @@ export default {
78
78
  params.catchFunction();
79
79
  }else{
80
80
  const axiosError= error as AxiosError;
81
- return Promise.reject(new Error(axiosError.message));
81
+ return Promise.reject(axiosError);
82
82
  }
83
83
  });
84
84
  return response?.data;
@@ -51,8 +51,8 @@ export const usePlayerLive = (hlsReady: Ref<boolean>)=>{
51
51
  }
52
52
 
53
53
  function playLive() {
54
- if (!playerStore.playerLive) return;
55
- playerStore.playerUpdatePlayerHlsUrl(`${apiStore.hlsUrl}live/dev.${playerStore.playerLive.conferenceId}/index.m3u8`);
54
+ if (!playerStore.playerHlsIdentifier) return;
55
+ playerStore.playerUpdatePlayerHlsUrl(`${apiStore.hlsUrl}live/${playerStore.playerHlsIdentifier}/index.m3u8`);
56
56
  playHls();
57
57
  }
58
58
 
@@ -2,17 +2,19 @@ import classicApi from "../../../api/classicApi";
2
2
  import { MediaRadio, MetadataRadio, NextAdvertising } from '@/stores/class/general/player';
3
3
  import { Podcast } from '@/stores/class/general/podcast';
4
4
  import dayjs from 'dayjs';
5
- import radioHelper from "../../../helper/radio/radioHelper";
6
5
  import {onBeforeUnmount, Ref, ref} from 'vue';
6
+ import { useI18n } from "vue-i18n";
7
7
  export const useFetchRadio = ()=>{
8
8
 
9
9
  const radioInterval : Ref<ReturnType<typeof setTimeout> | undefined> = ref(undefined);
10
+
11
+ const {t} = useI18n();
10
12
 
11
13
  async function fetchRadioMetadata(
12
14
  canalId: number,
13
15
  previousTitle: string,
14
16
  callbackMetadata: (
15
- metadata: MediaRadio,
17
+ metadata: MediaRadio|undefined,
16
18
  podcast: Podcast | undefined,
17
19
  history: Array<MediaRadio>
18
20
  ) => void,
@@ -33,15 +35,19 @@ export const useFetchRadio = ()=>{
33
35
  callbackAdvertising(metadata.nextAdvertising);
34
36
  }
35
37
  const arrayMetadata = metadata.previously;
36
- arrayMetadata.unshift(metadata.currently);
37
- for (let index = 0, len = arrayMetadata.length; index < len; index++) {
38
- if (
39
- dayjs().valueOf() - 18000 >
40
- dayjs(arrayMetadata[index].startDate).valueOf()
41
- ) {
42
- await useCallbackIfNewMetadata(previousTitle, arrayMetadata, index, len,callbackMetadata);
43
- return;
38
+ if(null!==metadata.currently){
39
+ arrayMetadata.unshift(metadata.currently);
40
+ for (let index = 0, len = arrayMetadata.length; index < len; index++) {
41
+ if (
42
+ dayjs().valueOf() - 18000 >
43
+ dayjs(arrayMetadata[index].startDate).valueOf()
44
+ ) {
45
+ await useCallbackIfNewMetadata(previousTitle, arrayMetadata, index, len,callbackMetadata);
46
+ return;
47
+ }
44
48
  }
49
+ }else{
50
+ callbackMetadata(undefined, undefined, arrayMetadata);
45
51
  }
46
52
  }
47
53
  async function useCallbackIfNewMetadata(previousTitle: string, arrayMetadata: Array<MediaRadio>, index:number, len: number, callbackMetadata: (
@@ -63,11 +69,22 @@ export const useFetchRadio = ()=>{
63
69
  }
64
70
  }
65
71
  }
66
- function displayTitle(metadata: MediaRadio): string {
67
- return radioHelper.displayTitle(metadata);
72
+ function displayTitle(metadata: MediaRadio|undefined): string {
73
+ if(!metadata){
74
+ return t("Silent stream");
75
+ }
76
+ let title = "";
77
+ if (metadata?.title) {
78
+ title += metadata.title;
79
+ }
80
+ if (metadata?.artist) {
81
+ title += " - " + metadata.artist;
82
+ }
83
+ return title;
68
84
  }
69
85
 
70
86
 
87
+
71
88
  onBeforeUnmount(() => {
72
89
  clearInterval(radioInterval.value as unknown as number);
73
90
  })
@@ -17,6 +17,8 @@
17
17
  :is-disabled="isDisabled"
18
18
  :no-deselect="noDeselect"
19
19
  :display-required="displayRequired"
20
+ :popover="popover"
21
+ :popover-relative-class="popoverRelativeClass"
20
22
  @on-search="onSearchCategory"
21
23
  @selected="onCategorySelected"
22
24
  />
@@ -52,6 +54,8 @@ const props = defineProps({
52
54
  displayLabel: { default: false, type: Boolean },
53
55
  textDanger :{ default: undefined, type: String },
54
56
  displayRequired: { default: false, type: Boolean },
57
+ popover: { default: undefined, type: String },
58
+ popoverRelativeClass: { default: undefined, type: String },
55
59
  })
56
60
 
57
61
  //Emits
@@ -116,8 +116,8 @@ const { t } = useI18n();
116
116
  const {handle403} = useErrorHandler();
117
117
 
118
118
  //Computed
119
- const changed = computed(() => `${props.size}|${props.reload}|${dsize.value}|${props.stateFilter}|${props.podcast?.podcastId}|${props.organisationId}`);
120
119
  const isNotAnAnswerList = computed(() => undefined === props.answerToComment);
120
+ const changed = computed(() => `${props.size}|${props.reload}|${dsize.value}|${props.stateFilter}|${props.podcast?.podcastId}|${props.organisationId}`);
121
121
  const sortChoice = computed(() =>{
122
122
  return [
123
123
  { title: t("The most recent"), value: "DATE_DESC" },
@@ -13,9 +13,9 @@
13
13
  :class="isVertical ? 'flex-column' : ''"
14
14
  >
15
15
  <img
16
- v-lazy="useProxyImageUrl(emission.imageUrl, isVertical ? '400' : '250')"
17
- :width="isVertical ? '400' : '250'"
18
- :height="isVertical ? '400' : '250'"
16
+ v-lazy="useProxyImageUrl(emission.imageUrl, tailleImage)"
17
+ :width="tailleImage"
18
+ :height="tailleImage"
19
19
  :class="isVertical ? 'img-box-bigger' : ''"
20
20
  class="img-box"
21
21
  aria-hidden="true"
@@ -49,7 +49,7 @@ import {useResizePhone} from "../../composable/useResizePhone";
49
49
  import { Emission } from "@/stores/class/general/emission";
50
50
  import {useImageProxy} from "../../composable/useImageProxy";
51
51
  import displayHelper from "../../../helper/displayHelper";
52
- import { nextTick, useTemplateRef, watch } from "vue";
52
+ import { nextTick, useTemplateRef, watch, computed } from "vue";
53
53
  import { useI18n } from "vue-i18n";
54
54
 
55
55
  //Props
@@ -69,6 +69,13 @@ const { t } = useI18n();
69
69
  const { isPhone } = useResizePhone();
70
70
  const { useProxyImageUrl } = useImageProxy();
71
71
 
72
+ // Computed
73
+ // Calcul de la taille de l'image
74
+ const tailleImage = computed(() => {
75
+ // L'élément fait 400 de large à la verticale, mais on prend en compte les bordures
76
+ return props.isVertical ? '396' : '250';
77
+ });
78
+
72
79
  //Watch
73
80
  watch(isPhone, async () => {
74
81
  nextTick(() => {
@@ -114,8 +121,9 @@ function urlify(text:string|undefined){
114
121
  }
115
122
 
116
123
  .img-box-bigger {
117
- width: 400px;
118
- height: 400px;
124
+ // L'élément fait 400 de large à la verticale, mais on prend en compte les bordures
125
+ width: 396px;
126
+ height: 396px;
119
127
  }
120
128
  }
121
129
  </style>
@@ -28,7 +28,7 @@ import ClassicDatePicker from "../../form/ClassicDatePicker.vue";
28
28
  import { ref, watch } from "vue";
29
29
  import { useI18n } from "vue-i18n";
30
30
 
31
- //Props
31
+ //Props
32
32
  const props = defineProps({
33
33
  isEmission: { default: false, type: Boolean },
34
34
  fromDate: { default: undefined, type: String },
@@ -38,7 +38,7 @@ const props = defineProps({
38
38
  //Emits
39
39
  const emit = defineEmits(["updateDates"]);
40
40
 
41
- //Data
41
+ //Data
42
42
  const isActive = ref([false, false]);
43
43
  const internDates = ref([
44
44
  dayjs().subtract(10, "days").startOf("day").toDate(),
@@ -50,6 +50,17 @@ const { t } = useI18n();
50
50
 
51
51
 
52
52
  //Watch
53
+ watch(isActive, () => {
54
+ emit("updateDates", {
55
+ from: isActive.value[0]
56
+ ? dayjs(internDates.value[0]).toISOString()
57
+ : undefined,
58
+ to: isActive.value[1]
59
+ ? dayjs(internDates.value[1]).toISOString()
60
+ : undefined,
61
+ });
62
+ }, { deep: true });
63
+
53
64
  watch(()=>props.toDate, () => {
54
65
  isActive.value[1] = undefined !== props.toDate;
55
66
  if (props.toDate && props.toDate !== internDates.value[1].toISOString()) {
@@ -75,6 +86,8 @@ watch(()=>props.fromDate, () => {
75
86
 
76
87
 
77
88
  //Methods
89
+
90
+
78
91
  function updateDate(index: number, value: Date): void {
79
92
  internDates.value[index] = value;
80
93
  if (
@@ -72,10 +72,7 @@ const currentlyPlayingString = computed(() => {
72
72
  if (playingRadio.value && playerStore.playerRadio) {
73
73
  return displayTitle(playerStore.playerRadio.metadata);
74
74
  }
75
- if (currentMetadata.value) {
76
- return displayTitle(currentMetadata.value);
77
- }
78
- return "";
75
+ return displayTitle(currentMetadata.value);
79
76
  });
80
77
 
81
78
  onMounted(()=>{
@@ -102,7 +99,7 @@ async function fetchCurrentlyPlaying(): Promise<void> {
102
99
  updateMetadata,
103
100
  );
104
101
  }
105
- function updateMetadata(metadata: MediaRadio, podcast?: Podcast): void {
102
+ function updateMetadata(metadata: MediaRadio|undefined, podcast?: Podcast): void {
106
103
  currentMetadata.value = metadata;
107
104
  currentPodcast.value = podcast;
108
105
  }
@@ -211,7 +211,10 @@ function play(isVideo: boolean): void {
211
211
  playerStore.playerPlay(
212
212
  {
213
213
  ...props.podcast,
214
- ...{ conferenceId: props.fetchConference?.conferenceId },
214
+ ...{
215
+ conferenceId: props.fetchConference?.conferenceId,
216
+ hlsIdentifier: props.fetchConference?.hlsIdentifier,
217
+ },
215
218
  },
216
219
  isVideo,
217
220
  );
@@ -7,7 +7,7 @@
7
7
  :display-label="displayLabel"
8
8
  :label="label ?? t('By rubric')"
9
9
  :text-danger="textDanger"
10
- :placeholder="t('Type string to filter by categories')"
10
+ :placeholder="placeholderText"
11
11
  :max-element="maxElement"
12
12
  :multiple="multiple"
13
13
  :min-search-length="1"
@@ -30,8 +30,14 @@ import { useI18n } from "vue-i18n";
30
30
  const props = defineProps({
31
31
  defaultanswer: { default: "", type: String },
32
32
  width: { default: "100%", type: String },
33
+ /**
34
+ * Active la sélection multiple
35
+ */
33
36
  multiple: { default: false, type: Boolean },
34
37
  reset: { default: false, type: Boolean },
38
+ /**
39
+ * Les rubriques à afficher
40
+ */
35
41
  allRubriques: { default: () => [], type: Array as () => Array<Rubrique> },
36
42
  rubriqueSelected: { default: undefined, type: Number },
37
43
  rubriqueSelectedArray: {
@@ -46,6 +52,10 @@ const props = defineProps({
46
52
  label:{default: undefined, type: String },
47
53
  displayLabel: { default: false, type: Boolean },
48
54
  textDanger :{ default: undefined, type: String },
55
+ /**
56
+ * Le texte affiché là où l'utilisateur doit effectuer sa saisie
57
+ */
58
+ placeholder: { type: String, required: false, default: undefined }
49
59
  })
50
60
 
51
61
 
@@ -55,7 +65,9 @@ const emit = defineEmits([
55
65
  "update:rubriqueSelectedArray",
56
66
  "selected"
57
67
  ]);
58
- //COmposables
68
+
69
+
70
+ //Composables
59
71
  const { t } = useI18n();
60
72
 
61
73
 
@@ -102,6 +114,16 @@ const model = computed({
102
114
  },
103
115
  })
104
116
 
117
+ /**
118
+ * Le texte à afficher dans la saisie de l'utilisateur
119
+ */
120
+ const placeholderText = computed(() => {
121
+ if (props.placeholder) {
122
+ return props.placeholder;
123
+ } else {
124
+ return t('Type string to filter by categories');
125
+ }
126
+ });
105
127
 
106
128
  //Watch
107
129
  watch(()=>props.rubriqueSelected, () => {
@@ -1,6 +1,8 @@
1
1
  <template>
2
2
  <div class="d-inline-flex w-100 mb-3 px-3 hide-phone">
3
3
  <div ref="rubriqueListContainer" class="rubrique-list-container">
4
+
5
+ <!-- Liste déroulante pour sélectionner le rubriquage -->
4
6
  <select
5
7
  v-model="rubriquage"
6
8
  :title="t('By topic')"
@@ -15,6 +17,8 @@
15
17
  {{ myRubriquage.title }}
16
18
  </option>
17
19
  </select>
20
+
21
+ <!-- Boutons de sélection de la rubrique -->
18
22
  <button
19
23
  v-for="rubrique in rubriqueDisplay"
20
24
  :id="'rubrique' + rubrique.rubriqueId"
@@ -25,6 +29,8 @@
25
29
  {{ rubrique.name }}
26
30
  </button>
27
31
  </div>
32
+
33
+ <!-- Bouton pour afficher les rubriques cachées -->
28
34
  <button
29
35
  v-show="hidenRubriques.length"
30
36
  id="rubriques-dropdown"
@@ -33,6 +39,8 @@
33
39
  >
34
40
  <PlusIcon />
35
41
  </button>
42
+
43
+ <!-- Popup de sélection des rubriques cachées -->
36
44
  <ClassicPopover
37
45
  ref="popoverRubrique"
38
46
  target="rubriques-dropdown"
@@ -43,6 +51,7 @@
43
51
  v-if="hidenRubriques.length"
44
52
  class="rubrique-chooser-minwidth"
45
53
  :all-rubriques="hidenRubriques"
54
+ :placeholder="rubriqueChooserText"
46
55
  @selected="addFilterFromPopover($event)"
47
56
  />
48
57
  </ClassicPopover>
@@ -107,6 +116,15 @@ const rubriquageDisplay = computed(() => {
107
116
  });
108
117
  });
109
118
 
119
+ // Retourne le texte à afficher dans le RubriqueChooser
120
+ const rubriqueChooserText = computed(() => {
121
+ if (!rubriquage.value) {
122
+ return '';
123
+ }
124
+ let topic = rubriquage.value.title;
125
+ return t('Enter name of topic', { topic });
126
+ });
127
+
110
128
 
111
129
  //Watch
112
130
  watch(()=>filterStore.filterRubrique, () => {
@@ -36,12 +36,6 @@
36
36
  </div>
37
37
  </div>
38
38
  <ChooseEpisodesNumber v-else :episodes-number="episodesNumber" @update-number="emit('update:episodesNumber', $event)"/>
39
- <ClassicCheckbox
40
- :text-init="proceedReading"
41
- id-checkbox="proceed-reading-checkbox"
42
- :label="t('Proceed reading')"
43
- @update:text-init="emit('update:proceedReading', $event)"
44
- />
45
39
  </template>
46
40
  <ClassicCheckbox
47
41
  v-if="displayIsVisible"
@@ -104,7 +98,6 @@ const props = defineProps({
104
98
  displayArticleParam: { default: false, type: Boolean },
105
99
  displayIsVisible: { default: false, type: Boolean },
106
100
  displayInsertCode: { default: false, type: Boolean },
107
- proceedReading: { default: true, type: Boolean },
108
101
  displayArticle: { default: true, type: Boolean },
109
102
  displayTranscript: { default: true, type: Boolean },
110
103
  displayWave: { default: true, type: Boolean },
@@ -118,7 +111,6 @@ const props = defineProps({
118
111
  //Emits
119
112
  const emit = defineEmits([
120
113
  "episodeChoiceDisplay",
121
- "update:proceedReading",
122
114
  "update:isVisible",
123
115
  "update:episodesNumber",
124
116
  "update:displayArticle",
@@ -44,7 +44,6 @@
44
44
  v-model:display-article="displayArticle"
45
45
  v-model:display-transcript="displayTranscript"
46
46
  v-model:display-wave="displayWave"
47
- v-model:proceed-reading="proceedReading"
48
47
  v-model:is-visible="isVisible"
49
48
  v-model:player-auto-play="playerAutoPlay"
50
49
  v-model:episodes-number="episodesNumber"
@@ -125,7 +124,6 @@ const iFrameModel = ref("default");
125
124
  const isShareModal = ref(false);
126
125
  const color = ref("#40a372");
127
126
  const theme = ref("#000000");
128
- const proceedReading = ref(true);
129
127
  const episodeChoiceDisplay = ref("number");
130
128
  const episodesNumber = ref(3);
131
129
  const isVisible = ref(false);
@@ -341,9 +339,6 @@ function addUrlParameters(url: Array<string>) {
341
339
  url.push(
342
340
  `&color=${color.value.substring(1)}&theme=${theme.value.substring(1)}`,
343
341
  );
344
- if (!proceedReading.value) {
345
- url.push("&proceed=false");
346
- }
347
342
  if (!displayArticle.value && displayArticleParam.value) {
348
343
  url.push("&article=false");
349
344
  }
@@ -78,7 +78,7 @@ import RssIcon from "vue-material-design-icons/Rss.vue";
78
78
  import { useApiStore } from "../../../stores/ApiStore";
79
79
  import ClassicPopover from "../../misc/ClassicPopover.vue";
80
80
  import { Emission } from "@/stores/class/general/emission";
81
- import { computed, Ref, ref, useTemplateRef, watch } from "vue";
81
+ import { computed, onMounted, Ref, ref, useTemplateRef, watch } from "vue";
82
82
  import { useI18n } from "vue-i18n";
83
83
  type Link = {
84
84
  name: string;
@@ -204,7 +204,9 @@ const rssUrl = computed(() => {
204
204
 
205
205
 
206
206
  //Watch
207
- watch(()=>props.windowWidth, () =>resizeWindow(), {immediate: true});
207
+ watch(()=>props.windowWidth, () =>resizeWindow());
208
+
209
+ onMounted(()=>resizeWindow());
208
210
 
209
211
 
210
212
  //Methods
@@ -12,6 +12,7 @@
12
12
  >{{ label }}
13
13
  <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/>
14
14
  </component>
15
+ <slot name="afterTitle"/>
15
16
  <template v-if="popover">
16
17
  <button
17
18
  :id="'popover' + inputId"
@@ -31,7 +32,9 @@
31
32
  <!-- eslint-enable -->
32
33
  </ClassicPopover>
33
34
  </template>
35
+ <slot name="afterHelp"/>
34
36
  </div>
37
+ <slot name="betweenTitleInput"/>
35
38
  <input
36
39
  v-if="!isWysiwyg && !isTextarea"
37
40
  v-show="showField"
@@ -7,11 +7,31 @@
7
7
  }"
8
8
  :style="{ width: width, height: height }"
9
9
  >
10
- <label :class="displayLabel ? '' : 'd-none'" :for="id" class="form-label">{{
11
- label
12
- }}
13
- <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/>
14
- </label>
10
+ <div class="d-flex align-items-center">
11
+ <label :class="displayLabel ? '' : 'd-none'" :for="id" class="form-label">{{
12
+ label
13
+ }}
14
+ <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/>
15
+ </label>
16
+ <template v-if="popover">
17
+ <button
18
+ :id="'popover' + id"
19
+ :title="t('Help')"
20
+ class="btn-transparent"
21
+ >
22
+ <HelpCircleIcon :size="30" />
23
+ </button>
24
+ <ClassicPopover
25
+ :target="'popover' + id"
26
+ popover-class="popover-z-index"
27
+ :relative-class="popoverRelativeClass"
28
+ >
29
+ <!-- eslint-disable vue/no-v-html -->
30
+ <div v-html="popover" />
31
+ <!-- eslint-enable -->
32
+ </ClassicPopover>
33
+ </template>
34
+ </div>
15
35
  <vSelect
16
36
  v-model="optionSelected"
17
37
  :input-id="id"
@@ -77,12 +97,15 @@
77
97
  </template>
78
98
 
79
99
  <script setup lang="ts">
80
- import { computed, ref, Ref, watch } from "vue";
100
+ import { computed, defineAsyncComponent, ref, Ref, watch } from "vue";
81
101
  import { useI18n } from "vue-i18n";
82
102
  import AsteriskIcon from "vue-material-design-icons/Asterisk.vue";
83
103
  import ChevronDownIcon from "vue-material-design-icons/ChevronDown.vue";
84
104
  import vSelect from "vue-select";
85
-
105
+ import HelpCircleIcon from "vue-material-design-icons/HelpCircle.vue";
106
+ const ClassicPopover = defineAsyncComponent(
107
+ () => import("../misc/ClassicPopover.vue"),
108
+ );
86
109
 
87
110
  //Props
88
111
  const props = defineProps({
@@ -106,6 +129,8 @@ const props = defineProps({
106
129
  allowEmpty: { default: true, type: Boolean },
107
130
  textDanger :{ default: undefined, type: String },
108
131
  displayRequired: { default: false, type: Boolean },
132
+ popover: { default: undefined, type: String },
133
+ popoverRelativeClass: { default: undefined, type: String },
109
134
  })
110
135
 
111
136
  //Emits
@@ -214,6 +239,9 @@ defineExpose({
214
239
  height: 100%;
215
240
  }
216
241
 
242
+ .vs__search, .vs__search:focus{
243
+ border: var(--vs-selected-border-width) solid transparent;
244
+ }
217
245
  .vs__search:focus {
218
246
  min-width: 150px;
219
247
  }
@@ -20,11 +20,11 @@
20
20
  class="img-accordion"
21
21
  :src="imageUrl"
22
22
  aria-hidden="true"
23
- alt=""
24
-
23
+ alt=""
25
24
  />
26
- <span class="flex-grow-1">{{ title }}</span>
27
- <ChevronDownIcon :class="{ 'arrow-transform': isOpen }" />
25
+ <span>{{ title }}</span>
26
+ <slot name="afterTitle"/>
27
+ <ChevronDownIcon class="ms-auto" :class="{ 'arrow-transform': isOpen }" />
28
28
  </button>
29
29
  <div v-show="isOpen" class="body p-2">
30
30
  <slot />
@@ -16,7 +16,7 @@ defineProps({
16
16
  --size-spinner: 3rem;
17
17
  --size-spinner-section: calc(var(--size-spinner) / 20);
18
18
  --half-size-spinner: calc(var(--size-spinner) / 2);
19
-
19
+
20
20
  color: #000000;
21
21
  display: inline-block;
22
22
  position: relative;