@saooti/octopus-sdk 31.0.46 → 32.0.2

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 (37) hide show
  1. package/README.md +5 -0
  2. package/package.json +1 -1
  3. package/src/api/classicCrud.ts +5 -0
  4. package/src/assets/bootstrap-diff.scss +0 -1
  5. package/src/assets/form.scss +3 -7
  6. package/src/assets/general.scss +4 -1
  7. package/src/assets/multiselect.scss +0 -6
  8. package/src/assets/share.scss +1 -0
  9. package/src/components/display/comments/CommentInput.vue +0 -1
  10. package/src/components/display/comments/CommentItem.vue +5 -1
  11. package/src/components/display/emission/EmissionItem.vue +1 -1
  12. package/src/components/display/filter/AdvancedSearch.vue +6 -6
  13. package/src/components/display/list/ListPaginate.vue +1 -1
  14. package/src/components/display/list/Paginate.vue +0 -1
  15. package/src/components/display/playlist/PlaylistItem.vue +18 -27
  16. package/src/components/display/playlist/PodcastList.vue +1 -1
  17. package/src/components/display/podcasts/ParticipantDescription.vue +1 -1
  18. package/src/components/display/podcasts/PodcastFilterList.vue +1 -1
  19. package/src/components/display/podcasts/PodcastImage.vue +8 -3
  20. package/src/components/display/sharing/PlayerParameters.vue +1 -1
  21. package/src/components/display/sharing/ShareButtons.vue +5 -1
  22. package/src/components/display/sharing/ShareButtonsIntern.vue +12 -14
  23. package/src/components/display/sharing/SharePlayer.vue +0 -1
  24. package/src/components/display/sharing/SharePlayerColors.vue +2 -2
  25. package/src/components/display/sharing/SharePlayerTypes.vue +1 -1
  26. package/src/components/display/sharing/SubscribeButtons.vue +1 -1
  27. package/src/components/form/ClassicSearch.vue +1 -1
  28. package/src/components/misc/TopBar.vue +4 -5
  29. package/src/components/misc/modal/ClipboardModal.vue +4 -0
  30. package/src/components/misc/modal/MessageModal.vue +6 -0
  31. package/src/components/misc/modal/NewsletterModal.vue +140 -129
  32. package/src/components/misc/modal/QrCodeModal.vue +4 -0
  33. package/src/components/misc/modal/ShareModalPlayer.vue +4 -0
  34. package/src/components/mixins/player/playerLive.ts +1 -1
  35. package/src/components/pages/Playlist.vue +1 -1
  36. package/src/components/pages/Playlists.vue +2 -2
  37. package/public/img/article.png +0 -0
package/README.md CHANGED
@@ -637,3 +637,8 @@ See [Configuration Reference](https://cli.vuejs.org/config/).
637
637
  * 31.0.44 Début CRUD API
638
638
  * 31.0.45 Live
639
639
  * 31.0.46 Pb css
640
+
641
+
642
+ * 32.0.0 Passage en 32
643
+ * 32.0.1 Navigation clavier
644
+ * 32.0.2 Newsletter pour emission & playlist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "31.0.46",
3
+ "version": "32.0.2",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -14,6 +14,11 @@ enum ModuleApi {
14
14
  }
15
15
  /* eslint-disable */
16
16
  export default {
17
+ async fetchData<Type>(state: StoreState,moduleName: ModuleApi,wsPath:string): Promise<Type>{
18
+ console.log(state,moduleName,wsPath);
19
+ const response = await axios.get('/mock');
20
+ return response.data;
21
+ },
17
22
  async postData<Type>(state: StoreState,moduleName: ModuleApi,wsPath:string, elementToCreate: unknown): Promise<Type>{
18
23
  console.log(state,moduleName,wsPath);
19
24
  const response = await axios.post('/mock', elementToCreate, {
@@ -22,7 +22,6 @@
22
22
  &:focus,
23
23
  &:active,
24
24
  &.active {
25
- outline: none !important;
26
25
  box-shadow: none;
27
26
  }
28
27
  &:hover{
@@ -1,16 +1,13 @@
1
1
  .octopus-app{
2
- .input-no-outline{
3
- outline-width: 0 !important;
4
- }
5
- :-moz-focusring {
6
- outline: 0px solid black;
2
+ button.btn-transparent{
3
+ background: transparent;
4
+ border: 0;
7
5
  }
8
6
  .width-auto{
9
7
  width: auto !important;
10
8
  }
11
9
  select {
12
10
  background: white !important;
13
- outline-color: transparent !important;
14
11
  padding: 0.5rem;
15
12
  border: 0.1rem solid #dee2e6;
16
13
  border-radius: 0.3rem;
@@ -38,7 +35,6 @@
38
35
  height: 2rem;
39
36
  line-height: 1.2rem;
40
37
  max-width: 100%;
41
- outline: none;
42
38
  padding: 0.25rem 0.4rem;
43
39
  position: relative;
44
40
  -webkit-transition: background 0.2s, border 0.2s, color 0.2s, -webkit-box-shadow 0.2s;
@@ -13,6 +13,10 @@ body{
13
13
  overscroll-behavior-y: contain;
14
14
  }
15
15
  .octopus-app{
16
+ *:focus-visible{
17
+ outline: none;
18
+ box-shadow: 0 0 10px 1px $octopus-primary-color !important;
19
+ }
16
20
  a{
17
21
  word-break: break-word;
18
22
  }
@@ -138,7 +142,6 @@ body{
138
142
  }
139
143
  a, a:hover{
140
144
  text-decoration: none;
141
- outline-width: 0;
142
145
  }
143
146
  a.link-hover{
144
147
  color: black !important;
@@ -140,10 +140,6 @@
140
140
  box-sizing: border-box;
141
141
  }
142
142
 
143
- .multiselect:focus {
144
- outline: none;
145
- }
146
-
147
143
  .multiselect--disabled {
148
144
  background: #ededed;
149
145
  pointer-events: none;
@@ -195,7 +191,6 @@
195
191
  .multiselect__input:focus,
196
192
  .multiselect__single:focus {
197
193
  border-color: #a8a8a8;
198
- outline: none;
199
194
  }
200
195
 
201
196
  .multiselect__single {
@@ -392,7 +387,6 @@
392
387
 
393
388
  .multiselect__option--highlight {
394
389
  background: #f8f9fa;
395
- outline: none;
396
390
  color: #000;
397
391
  }
398
392
 
@@ -143,6 +143,7 @@
143
143
  display: flex;
144
144
  flex-direction: column;
145
145
  max-height: 13rem;
146
+ flex-grow: 1;
146
147
  @media (max-width: 450px) {
147
148
  padding: 0.5rem 0;
148
149
  text-align: center;
@@ -316,7 +316,6 @@ export default defineComponent({
316
316
  color: black;
317
317
  }
318
318
  textarea {
319
- outline-width: 0 !important;
320
319
  border-top: 0;
321
320
  border-right: 0;
322
321
  border-left: 0;
@@ -8,6 +8,7 @@
8
8
  />
9
9
  <template v-else>
10
10
  <input
11
+ ref="focusElement"
11
12
  v-model="temporaryName"
12
13
  class="form-input"
13
14
  type="text"
@@ -135,7 +136,7 @@ import { Podcast } from '@/store/class/general/podcast';
135
136
  import { Conference } from '@/store/class/conference/conference';
136
137
  import CommentBasicView from './CommentBasicView.vue';
137
138
  import Constants from '../../../../public/config';
138
- import { defineComponent, defineAsyncComponent } from 'vue';
139
+ import { defineComponent, defineAsyncComponent, nextTick } from 'vue';
139
140
  const CommentInput = defineAsyncComponent(() => import('./CommentInput.vue'));
140
141
  const CommentParentInfo = defineAsyncComponent(() => import('./CommentParentInfo.vue'));
141
142
  const EditCommentBox = defineAsyncComponent(() => import('@/components/display/edit/EditCommentBox.vue'));
@@ -250,6 +251,9 @@ export default defineComponent({
250
251
  this.temporaryName = this.comment.name && null !== this.comment.name ? this.comment.name : '';
251
252
  this.temporaryContent = this.comment.content && null !== this.comment.content ? this.comment.content : '';
252
253
  this.isEditing = true;
254
+ this.$nextTick(() => {
255
+ (this.$refs.focusElement as HTMLElement)?.focus();
256
+ });
253
257
  },
254
258
  validEdit(): void {
255
259
  const comment = this.comment;
@@ -9,7 +9,7 @@
9
9
  query: { productor: filterOrga },
10
10
  }"
11
11
  :title="$t('Emission')"
12
- class="d-flex text-dark"
12
+ class="d-flex flex-grow-1 text-dark"
13
13
  >
14
14
  <img
15
15
  v-lazy="emission.imageUrl"
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <div>
3
- <div
4
- class="d-flex justify-content-center mb-3 text-secondary c-hand"
2
+ <div class="d-flex flex-column justify-content-center align-items-center">
3
+ <button
4
+ class="d-flex justify-content-center mb-3 text-secondary btn-transparent"
5
5
  @click="showFilters = !showFilters"
6
6
  >
7
7
  <div>{{ $t('Advanced filters') }}</div>
@@ -9,7 +9,7 @@
9
9
  class="h3 saooti-arrow_down m-0"
10
10
  :class="{ 'arrow-transform': showFilters }"
11
11
  />
12
- </div>
12
+ </button>
13
13
  <div
14
14
  v-show="showFilters"
15
15
  class="advanced-search-container"
@@ -53,7 +53,7 @@
53
53
  >
54
54
  <template #default="{ inputValue, inputEvents }">
55
55
  <input
56
- class="px-2 py-1 border rounded focus:outline-none focus:border-blue-300"
56
+ class="px-2 py-1 border rounded focus:border-blue-300"
57
57
  :value="inputValue"
58
58
  v-on="inputEvents"
59
59
  >
@@ -77,7 +77,7 @@
77
77
  >
78
78
  <template #default="{ inputValue, inputEvents }">
79
79
  <input
80
- class="px-2 py-1 border rounded focus:outline-none focus:border-blue-300"
80
+ class="px-2 py-1 border rounded focus:border-blue-300"
81
81
  :value="inputValue"
82
82
  v-on="inputEvents"
83
83
  >
@@ -8,7 +8,7 @@
8
8
  :error-text="errorText"
9
9
  />
10
10
  <template v-if="!loading">
11
- <div class="paginate-section page-box">
11
+ <div class="paginate-section mb-2 page-box">
12
12
  <div class="text-secondary">
13
13
  <template v-if="textCount && (windowWidth > 1300 || windowWidth<=960)">
14
14
  {{ textCount }}
@@ -207,7 +207,6 @@ export default defineComponent({
207
207
  border-right: 0;
208
208
  border-left: 0;
209
209
  background: transparent !important;
210
- outline-width: 0;
211
210
  }
212
211
  .btn{
213
212
  border-radius: 0;
@@ -10,23 +10,14 @@
10
10
  query: { productor: $store.state.filter.organisationId },
11
11
  }"
12
12
  :title="$t('Playlist')"
13
- class="text-dark"
13
+ class="d-flex flex-grow-1 text-dark"
14
14
  >
15
15
  <img
16
16
  v-lazy="playlist.imageUrl"
17
17
  :title="$t('Playlist name image', {name:name})"
18
18
  class="img-box"
19
19
  >
20
- </router-link>
21
- <div class="emission-item-text">
22
- <router-link
23
- :to="{
24
- name: 'playlist',
25
- params: { playlistId: playlist.playlistId },
26
- query: { productor: $store.state.filter.organisationId },
27
- }"
28
- class="text-dark"
29
- >
20
+ <div class="emission-item-text">
30
21
  <div class="emission-name">
31
22
  <img
32
23
  v-if="!activePlaylist && !isPodcastmaker"
@@ -46,22 +37,22 @@
46
37
  />
47
38
  <!-- eslint-enable -->
48
39
  </div>
49
- </router-link>
50
- <div class="flex-grow-1" />
51
- <router-link
52
- v-if="!isPodcastmaker && playlist.organisation"
53
- :to="{
54
- name: 'productor',
55
- params: { productorId: playlist.organisation.id },
56
- query: { productor: $store.state.filter.organisationId },
57
- }"
58
- class="text-dark"
59
- >
60
- <div class="emission-producer primary-darker">
61
- © {{ playlist.organisation.name }}
62
- </div>
63
- </router-link>
64
- </div>
40
+ <div class="flex-grow-1" />
41
+ <router-link
42
+ v-if="!isPodcastmaker && playlist.organisation"
43
+ :to="{
44
+ name: 'productor',
45
+ params: { productorId: playlist.organisation.id },
46
+ query: { productor: $store.state.filter.organisationId },
47
+ }"
48
+ class="text-dark"
49
+ >
50
+ <div class="emission-producer primary-darker">
51
+ © {{ playlist.organisation.name }}
52
+ </div>
53
+ </router-link>
54
+ </div>
55
+ </router-link>
65
56
  </li>
66
57
  </template>
67
58
 
@@ -6,7 +6,7 @@
6
6
  <ClassicSearch
7
7
  v-if="!loading && notEmptyPlaylist"
8
8
  v-model:textInit="searchPattern"
9
- class="width-600 align-self-baseline"
9
+ class="width-600 align-self-baseline mb-2"
10
10
  id-checkbox="podcast-list-search"
11
11
  :label="$t('Search')"
12
12
  />
@@ -7,7 +7,7 @@
7
7
  <span
8
8
  :id="idPopover"
9
9
  role="button"
10
- tabindex="-1"
10
+ tabindex="0"
11
11
  class="saooti-help m-0"
12
12
  :title="title"
13
13
  />
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="p-3">
3
3
  <h2>{{ titleFilter }}</h2>
4
- <div class="d-flex align-items-center flex-wrap">
4
+ <div class="d-flex align-items-center flex-wrap mb-2">
5
5
  <div
6
6
  class="d-flex align-items-center flex-grow-1 me-3"
7
7
  >
@@ -29,7 +29,7 @@
29
29
  >
30
30
  {{ $t('Recorded in live') }}
31
31
  </div>
32
- <div
32
+ <button
33
33
  v-if="hidePlay || recordingLive"
34
34
  class="podcast-image-play-button"
35
35
  :class="classicPodcastPlay ? '' : 'transparent-background'"
@@ -74,7 +74,7 @@
74
74
  >
75
75
  {{ textVisible }}
76
76
  </div>
77
- </div>
77
+ </button>
78
78
  <div
79
79
  v-if="displayDescription && isMobile"
80
80
  class="background-icon primary-bg saooti-arrow-up2"
@@ -330,7 +330,7 @@ export default defineComponent({
330
330
  .transparent-background {
331
331
  background-color: rgba(255, 255, 255, 0.5);
332
332
  }
333
- .podcast-image-play-button {
333
+ .podcast-image-play-button{
334
334
  position: absolute;
335
335
  display: flex;
336
336
  align-items: center;
@@ -341,6 +341,11 @@ export default defineComponent({
341
341
  bottom: 0;
342
342
  cursor: pointer;
343
343
  flex-direction: column;
344
+ background: transparent;
345
+ border-width: 0;
346
+ &:focus{
347
+ background: rgba(0, 0, 0, 0.5);
348
+ }
344
349
 
345
350
  .icon-container {
346
351
  background: #00000050;
@@ -62,7 +62,7 @@
62
62
  type="number"
63
63
  min="1"
64
64
  max="50"
65
- class="input-share-player input-no-outline text-center m-2"
65
+ class="input-share-player text-center m-2"
66
66
  >
67
67
  <label
68
68
  for="number-input"
@@ -11,7 +11,7 @@
11
11
  v-if="authenticated"
12
12
  id="popover-share-help"
13
13
  role="button"
14
- tabindex="-1"
14
+ tabindex="0"
15
15
  class="saooti-help ms-2 align-items-start"
16
16
  :title="$t('Help')"
17
17
  />
@@ -27,6 +27,7 @@
27
27
  <ShareButtonsIntern
28
28
  :podcast="podcast"
29
29
  :emission="emission"
30
+ :playlist="playlist"
30
31
  :participant-id="participantId"
31
32
  :organisation-id="organisationId"
32
33
  :not-exclusive="notExclusive"
@@ -40,6 +41,7 @@
40
41
  <ShareButtonsIntern
41
42
  :podcast="podcast"
42
43
  :emission="emission"
44
+ :playlist="playlist"
43
45
  :participant-id="participantId"
44
46
  :organisation-id="organisationId"
45
47
  :not-exclusive="notExclusive"
@@ -56,6 +58,7 @@ import { displayMethods } from '../../mixins/functions';
56
58
  import Popover from '../../misc/Popover.vue';
57
59
  import ShareButtonsIntern from './ShareButtonsIntern.vue';
58
60
  import { defineComponent } from 'vue';
61
+ import { Playlist } from '@/store/class/general/playlist';
59
62
  export default defineComponent({
60
63
  components: {
61
64
  ShareButtonsIntern,
@@ -65,6 +68,7 @@ export default defineComponent({
65
68
  props: {
66
69
  podcast: { default: undefined, type: Object as ()=> Podcast},
67
70
  emission: { default: undefined, type: Object as ()=> Emission},
71
+ playlist: { default: undefined, type: Object as ()=>Playlist},
68
72
  participantId: { default: undefined, type: Number},
69
73
  organisationId: { default: undefined, type: String},
70
74
  notExclusive: { default: true, type: Boolean},
@@ -42,34 +42,28 @@
42
42
  >
43
43
  <div class="saooti-rss-bounty" />
44
44
  </a>
45
- <a
46
- rel="noopener"
47
- target="_blank"
45
+ <button
48
46
  :class="getClass()"
49
47
  :title="$t('Copy this page URL')"
50
48
  @click="onCopyCode(urlPage,afterCopy)"
51
49
  >
52
50
  <div class="saooti-link" />
53
- </a>
54
- <a
55
- v-if="podcast"
56
- rel="noopener"
57
- target="_blank"
51
+ </button>
52
+ <button
53
+ v-if="podcast || emission ||playlist"
58
54
  :class="getClass()"
59
55
  :title="$t('Share newsletter')"
60
56
  @click="newsletter = true"
61
57
  >
62
58
  <div class="saooti-newsletter" />
63
- </a>
64
- <a
65
- rel="noopener"
66
- target="_blank"
59
+ </button>
60
+ <button
67
61
  :class="getClass()"
68
62
  :title="$t('Share QR Code')"
69
63
  @click="qrCode = true"
70
64
  >
71
65
  <div class="saooti-qrcode" />
72
- </a>
66
+ </button>
73
67
  <ClipboardModal
74
68
  v-if="dataRSSSave"
75
69
  :link="rssUrl"
@@ -81,6 +75,8 @@
81
75
  v-if="newsletter"
82
76
  :closable="true"
83
77
  :podcast="podcast"
78
+ :emission="emission"
79
+ :playlist="playlist"
84
80
  @close="newsletter = false"
85
81
  />
86
82
  <QrCodeModal
@@ -104,6 +100,7 @@ import Snackbar from '../../misc/Snackbar.vue';
104
100
  import { displayMethods } from '../../mixins/functions';
105
101
  import { defineComponent, defineAsyncComponent } from 'vue';
106
102
  import SnackbarVue from '../../misc/Snackbar.vue';
103
+ import { Playlist } from '@/store/class/general/playlist';
107
104
  const ClipboardModal = defineAsyncComponent(() => import('../../misc/modal/ClipboardModal.vue'));
108
105
  const NewsletterModal = defineAsyncComponent(() => import('../../misc/modal/NewsletterModal.vue'));
109
106
  const QrCodeModal = defineAsyncComponent(() => import('../../misc/modal/QrCodeModal.vue'));
@@ -120,6 +117,7 @@ export default defineComponent({
120
117
  props: {
121
118
  podcast: { default: undefined, type: Object as ()=> Podcast},
122
119
  emission: { default: undefined, type: Object as ()=> Emission},
120
+ playlist: { default: undefined, type: Object as ()=>Playlist},
123
121
  participantId: { default: undefined, type: Number},
124
122
  organisationId: { default: undefined, type: String},
125
123
  notExclusive: { default: true, type: Boolean},
@@ -195,7 +193,7 @@ export default defineComponent({
195
193
 
196
194
  methods: {
197
195
  getClass(className='btn-rss'): string{
198
- let returnString = `btn ${className} share-btn mb-2`;
196
+ let returnString = `btn ${className} share-btn mb-2 text-dark`;
199
197
  returnString+= this.verticalDisplay ? '' : ' mx-2';
200
198
  return returnString;
201
199
  },
@@ -291,7 +291,6 @@ export default defineComponent({
291
291
  color: white;
292
292
  font-weight: bold;
293
293
  letter-spacing: 1px;
294
- outline: none;
295
294
  box-shadow: 10px 10px 34px -15px hsla(0, 0%, 0%, 0.4);
296
295
  border-radius: 255px 15px 225px 15px/15px 225px 15px 255px;
297
296
  border: solid 2px #41403e;
@@ -4,7 +4,7 @@
4
4
  <div>{{ $t('Choose color') }}</div>
5
5
  <VSwatches
6
6
  v-model="internColor"
7
- class="c-hand input-no-outline"
7
+ class="c-hand "
8
8
  show-fallback
9
9
  colors="text-advanced"
10
10
  popover-to="right"
@@ -15,7 +15,7 @@
15
15
  <div>{{ $t('Choose theme') }}</div>
16
16
  <VSwatches
17
17
  v-model="internTheme"
18
- class="c-hand input-no-outline"
18
+ class="c-hand "
19
19
  show-fallback
20
20
  colors="text-advanced"
21
21
  popover-to="right"
@@ -7,7 +7,7 @@
7
7
  <select
8
8
  id="iframe-select"
9
9
  :value="iFrameModel"
10
- class="input-no-outline"
10
+ class=""
11
11
  @change="$emit('update:iFrameModel',$event.target.value)"
12
12
  >
13
13
  <template
@@ -45,7 +45,7 @@ export default defineComponent({
45
45
  {name:'applePodcast', icon:'saooti-apple', url : this.getUrl('applePodcast')},
46
46
  {name:'deezer', icon:'saooti-deezer', url : this.getUrl('deezer')},
47
47
  {name:'googlePodcasts', icon:"saooti-google-podcasts", url : this.getUrl('googlePodcasts')},
48
- {name:'playerFm', icon: 'saooti-saooti-playerfm', url : this.getUrl('playerFm')},
48
+ {name:'playerFm', icon: 'saooti-playerfm', url : this.getUrl('playerFm')},
49
49
  {name:'pocketCasts', icon:'saooti-pocket-casts', url : this.getUrl('pocketCasts')},
50
50
  {name:'podcastAddict', icon: 'saooti-podcast-addict', url : this.getUrl('podcastAddict')},
51
51
  {name:'radioline', icon:'saooti-radioline', url : this.getUrl('radioline')},
@@ -5,7 +5,7 @@
5
5
  ref="search"
6
6
  v-model="textValue"
7
7
  type="text"
8
- class="search-input w-100 p-2 input-no-outline"
8
+ class="search-input w-100 p-2 "
9
9
  :placeholder="label"
10
10
  :autofocus="autofocus"
11
11
  >
@@ -46,8 +46,8 @@
46
46
  </router-link>
47
47
  </template>
48
48
  </div>
49
- <div
50
- class="saooti-burger-menu"
49
+ <button
50
+ class="btn-transparent saooti-burger-menu"
51
51
  :title="$t('open left Menu')"
52
52
  @click="onDisplayMenu(false)"
53
53
  />
@@ -63,9 +63,8 @@
63
63
  name: 'podcasts',
64
64
  query: { productor: $store.state.filter.organisationId },
65
65
  }"
66
- >
67
- <div class="btn admin-button m-1 saooti-search" />
68
- </router-link>
66
+ class="btn admin-button m-1 saooti-search"
67
+ />
69
68
  </div>
70
69
  </div>
71
70
  </div>
@@ -8,6 +8,7 @@
8
8
  {{ $t('RSS Link') }}
9
9
  </div>
10
10
  <button
11
+ ref="focusElement"
11
12
  type="button"
12
13
  class="btn-close btn-close-white"
13
14
  title="Close"
@@ -53,6 +54,9 @@ export default defineComponent({
53
54
  emission: { default: undefined, type: Object as ()=> Emission},
54
55
  },
55
56
  emits: ['close', 'copy'],
57
+ mounted(){
58
+ (this.$refs.focusElement as HTMLElement)?.focus();
59
+ },
56
60
 
57
61
  methods: {
58
62
  closePopup(): void {
@@ -12,6 +12,7 @@
12
12
  </h5>
13
13
  <button
14
14
  v-if="closable"
15
+ :ref="closable?'focusElement':''"
15
16
  type="button"
16
17
  class="btn-close btn-close-white"
17
18
  title="Close"
@@ -32,6 +33,7 @@
32
33
  >
33
34
  <button
34
35
  v-if="canceltext"
36
+ :ref="!closable && canceltext?'focusElement':''"
35
37
  class="btn m-1"
36
38
  @click="onCancel"
37
39
  >
@@ -46,6 +48,7 @@
46
48
  </button>
47
49
  <button
48
50
  class="btn btn-primary m-1"
51
+ :ref="!closable && !canceltext?'focusElement':''"
49
52
  @click="onValid"
50
53
  >
51
54
  {{ validatetext }}
@@ -70,6 +73,9 @@ export default defineComponent({
70
73
  thirdText: { default: undefined, type: String},
71
74
  },
72
75
  emits: ['close', 'validate', 'cancel', 'thirdEvent'],
76
+ mounted(){
77
+ (this.$refs.focusElement as HTMLElement)?.focus();
78
+ },
73
79
  methods: {
74
80
  closePopup(): void {
75
81
  this.$emit('close');
@@ -21,20 +21,30 @@
21
21
  <h4 class="mb-3">
22
22
  {{ $t('Configuration') }}
23
23
  </h4>
24
- <ClassicCheckbox
25
- v-model:textInit="displayEmissionName"
26
- id-checkbox="display-emission-name"
27
- :label="$t('Display emission name')"
28
- />
29
- <ClassicCheckbox
30
- v-model:textInit="displayParticipantsNames"
31
- id-checkbox="display-participants-names"
32
- :label="$t('Display participants list')"
33
- />
24
+ <label for="share-url-newsletter">{{$t('Share')}}</label>
25
+ <input
26
+ v-model="shareUrl"
27
+ id="share-url-newsletter"
28
+ class="form-input mb-2"
29
+ type="text"
30
+ :class="{ 'border border-danger': 0 === shareUrl }"
31
+ >
32
+ <template v-if="podcast">
33
+ <ClassicCheckbox
34
+ v-model:textInit="displayEmissionName"
35
+ id-checkbox="display-emission-name"
36
+ :label="$t('Display emission name')"
37
+ />
38
+ <ClassicCheckbox
39
+ v-model:textInit="displayParticipantsNames"
40
+ id-checkbox="display-participants-names"
41
+ :label="$t('Display participants list')"
42
+ />
43
+ </template>
34
44
  <div class="d-flex align-items-center mt-2">
35
45
  <VSwatches
36
46
  v-model="color"
37
- class="c-hand input-no-outline me-2 mt-2"
47
+ class="c-hand me-2 mt-2"
38
48
  show-fallback
39
49
  colors="text-advanced"
40
50
  popover-to="right"
@@ -101,6 +111,9 @@ import { Podcast } from '@/store/class/general/podcast';
101
111
  import { state } from '../../../store/paramStore';
102
112
  import { defineComponent } from 'vue'
103
113
  import SnackbarVue from '../../misc/Snackbar.vue';
114
+ import octopusApi from '@saooti/octopus-api';
115
+ import { Emission } from '@/store/class/general/emission';
116
+ import { Playlist } from '@/store/class/general/playlist';
104
117
  export default defineComponent({
105
118
  name: 'NewsletterModal',
106
119
 
@@ -113,7 +126,9 @@ export default defineComponent({
113
126
  mixins: [displayMethods],
114
127
 
115
128
  props: {
116
- podcast: { default: ()=>({}), type: Object as ()=> Podcast},
129
+ podcast: { default: undefined, type: Object as ()=> Podcast},
130
+ emission: { default: undefined, type: Object as ()=> Emission},
131
+ playlist: { default: undefined, type: Object as ()=>Playlist},
117
132
  },
118
133
 
119
134
  emits: ['close'],
@@ -123,164 +138,150 @@ export default defineComponent({
123
138
  displayParticipantsNames: true as boolean,
124
139
  displayEmissionName: true as boolean,
125
140
  color: '#40a372' as string,
126
- dummyParam: new Date().getTime().toString() as string,
141
+ shareUrl: window.location.href as string,
142
+
127
143
  };
128
144
  },
129
145
 
130
146
  computed: {
131
- resourcesUrl(): string{
132
- return state.podcastPage.resourceUrl? state.podcastPage.resourceUrl : window.location.origin;
147
+ date(): string {
148
+ if(!this.podcast || 1970 === moment(this.podcast.pubDate).year()){return '';}
149
+ return moment(this.podcast.pubDate).format('D MMMM YYYY, HH[h]mm');
150
+ },
151
+ duration(): string {
152
+ if (!this.podcast || this.podcast.duration <= 1) return '';
153
+ if (this.podcast.duration > 600000) {
154
+ return humanizeDuration(this.podcast.duration, {
155
+ language: this.$i18n.locale,
156
+ largest: 1,
157
+ round: true,
158
+ });
159
+ }
160
+ return humanizeDuration(this.podcast.duration, {
161
+ language: this.$i18n.locale,
162
+ largest: 2,
163
+ round: true,
164
+ });
133
165
  },
134
166
  emissionName(): string {
135
- if (this.displayEmissionName)
136
- return (
137
- `<tr><td colspan="2" style="font-size: 16px;line-height:24px;font-weight: bold;">` +
138
- this.podcast.emission.name +
139
- `</td></tr>`
140
- );
141
- return '';
167
+ if (!this.displayEmissionName || !this.podcast){return ''}
168
+ return (
169
+ `<tr><td colspan="2" style="font-size: 16px;line-height:24px;font-weight: bold;">${this.podcast.emission.name}</td></tr>`
170
+ );
142
171
  },
143
172
  articleHtml(): string{
144
- if(this.podcast.article && 0 !== this.podcast.article.length){
145
- return (`<a href="` +
146
- this.podcast.article +
147
- `" title="` +
148
- this.$t('See associated article') +
149
- `">
150
- <img width="44" height="44" style="display: inline-block;vertical-align: middle; margin-right:3px" src="` +
151
- this.resourcesUrl + `/img/article.png">
152
- </a>
153
- <a style="color: #000;text-decoration: none;" href="` +
154
- this.podcast.article +
155
- `">` +
156
- this.$t('See associated article') +
157
- `</a>`);
158
- }
159
- return '';
173
+ if (!this.podcast || this.podcast.article ||0 !== this.podcast.article?.length){return ''}
174
+ return (`<a href="${this.podcast.article}" title="${this.$t('See associated article')}">
175
+ <img width="44" height="44" style="display: inline-block;vertical-align: middle; margin-right:3px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA6UlEQVRIie3WPUpEMRTF8R9+4QpEBGttrcdeV+E2pp3KdYi7GBRttNVCZgOCjSuQ+UCLJzLIe7l3HpFpPJAuOf+T5F4SYh3jFZ/JMVlevJUwv8c+HvEQzD/FIBEaHOFtKdkosWb0PfdHGwXzOxxk03SpDVDNvA1Q1bwNcFMwn/cB/K6iQ+3VMsVVDQDcylVMSl1VBOea5FFjTXHWZVJqtCdcYjcI+YHnPoB3FY6qdERVVNrBHi6wGXgscK3Z8UqAE80dbAeAGV4wXhUwxk5gHurP72CtgP9Gw5oabYBhT7/wwZ/If09S35Yv52lVAXwyqt0AAAAASUVORK5CYII=">
176
+ </a>
177
+ <a style="color: #000;text-decoration: none;" href="${this.podcast.article}">${this.$t('See associated article')}</a>`);
160
178
  },
161
179
  participantsName(): string {
162
- if (!this.displayParticipantsNames || !this.podcast.animators) return '';
180
+ if (!this.displayParticipantsNames || !this.podcast || !this.podcast.animators) return '';
163
181
  const text = [''];
164
182
  this.podcast.animators.forEach((element: Participant) => {
165
183
  text.push(
166
184
  `<table width='100%' style="width:100%;background: #f3f3f3;font-family: Arial, sans-serif;font-size: 12px;line-height: 20px;border-bottom-left-radius: 1.5em;border-bottom-right-radius: 1.5em;">
167
185
  <tr>
168
186
  <td width="90" rowspan="2" style="text-align:left; vertical-align: top; width: 90px;padding:0 15px 15px 10px">
169
- <img width="72" style="width: 62px;height: 62px;border-radius: 50%;background-color: #fff;" src="` +
170
- element.imageUrl +
171
- `" alt="` +
172
- this.$t('Animator image') +
173
- `">
187
+ <img width="72" style="width: 62px;height: 62px;border-radius: 50%;background-color: #fff;" src="${element.imageUrl}" alt="${this.$t('Animator image')}">
174
188
  </td>
175
- <td height="1" style="height: 1px;text-align:left; font-size: 14px;line-height:20px;vertical-align: top;font-weight: bold;padding-top: 23px;">` +
176
- this.getName(element) +
177
- `</td>
189
+ <td height="1" style="height: 1px;text-align:left; font-size: 14px;line-height:20px;vertical-align: top;font-weight: bold;padding-top: 23px;">${this.getName(element)}</td>
178
190
  </tr>`
179
191
  );
180
192
  if (element.description) {
181
193
  text.push(
182
- `<tr>
183
- <td style="height: 100%;text-align:justify;padding-bottom: 15px;padding-right: 15px; font-size: 12px;line-height:16px;vertical-align: top">
184
- ` +
185
- element.description +
186
- `
187
- </td>
188
- </tr>`
194
+ `<tr><td style="height: 100%;text-align:justify;padding-bottom: 15px;padding-right: 15px; font-size: 12px;line-height:16px;vertical-align: top">
195
+ ${element.description}</td></tr>`
189
196
  );
190
197
  }
191
198
  text.push(`</table>`);
192
199
  });
193
200
  return text.join('');
194
201
  },
202
+ imageUrl():string{
203
+ if(this.podcast){
204
+ return `${this.podcast.imageUrl}" alt="${this.$t('Podcast image')}`;
205
+ }
206
+ if(this.emission){
207
+ return `${this.emission.imageUrl}" alt="${this.$t('Emission image')}`;
208
+ }
209
+ if(this.playlist){
210
+ return `${this.playlist.imageUrl}" alt="${this.$t('Playlist image')}`;
211
+ }
212
+ return '';
213
+ },
214
+ title():string{
215
+ if(this.podcast){
216
+ return this.podcast.title;
217
+ }
218
+ if(this.emission){
219
+ return this.emission.name;
220
+ }
221
+ if(this.playlist){
222
+ return this.playlist.title;
223
+ }
224
+ return '';
225
+ },
226
+ description():string{
227
+ if (this.podcast && this.podcast.description) {
228
+ return `<tr><td colspan="2" valign="top" style="line-height:24px;font-size: 14px;max-width: 500px;">${this.podcast.description}</td></tr>`;
229
+ }
230
+ if(this.emission && this.emission.description){
231
+ return `<tr><td colspan="2" valign="top" style="line-height:24px;font-size: 14px;max-width: 500px;">${this.emission.description}</td></tr>`;
232
+ }
233
+ if(this.playlist && this.playlist.description){
234
+ return `<tr><td colspan="2" valign="top" style="line-height:24px;font-size: 14px;max-width: 500px;">${this.playlist.description}</td></tr>`;
235
+ }
236
+ return '';
237
+ },
238
+ shareText():string{
239
+ if (this.podcast) {
240
+ return this.$t('Listen this episode');
241
+ }
242
+ if (this.emission) {
243
+ return this.$t('All podcast emission button');
244
+ }
245
+ return this.$t('Podcasts in the playlist');
246
+ },
247
+ durationPodcast():string{
248
+ if(!this.podcast){return ''}
249
+ return `<td colspan="2" style="height: 1px;color: #666;font-size: 12px;line-height: 16px;padding-top:15px;">
250
+ <span>${this.date}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
251
+ <span style="padding: 0 10px">${this.$t('Duration', { duration: this.duration })}</span>
252
+ </td>`;
253
+ },
195
254
  newsletterHtml(): string {
196
255
  const html = [
197
256
  `<table width='100%' style="width:100%;background:#f3f3f3;font-family: Arial, sans-serif;font-size: 12px;line-height: 20px;border-top-left-radius: 1.5em;border-top-right-radius: 1.5em;">
198
- <tr>
257
+ <tr>
199
258
  <td valign="top" rowspan="4" style="vertical-align: top; padding: 10px;">
200
- <img width="140" height="140" src="` +
201
- this.podcast.imageUrl +
202
- `" alt="` +
203
- this.$t('Podcast image') +
204
- `" style="width: 140px;border-radius: 16px; box-shadow: 0px 12px 48px 6px rgba(64, 163, 114, 0.2);">
205
- </td>
206
- <td colspan="2" style="height: 1px;color: #666;font-size: 12px;line-height: 16px;padding-top:15px;">
207
- <span>` +
208
- this.date +
209
- `</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="padding: 0 10px">` +
210
- this.$t('Duration', { duration: this.duration }) +
211
- `</span>
259
+ <img width="140" height="140" src="${this.imageUrl}" style="width: 140px;border-radius: 16px; box-shadow: 0px 12px 48px 6px rgba(64, 163, 114, 0.2);">
212
260
  </td>
261
+ ${this.durationPodcast}
213
262
  </tr>
214
263
  <tr>
215
- <td colspan="2" valign="top" style="line-height:24px;color: ` +
216
- this.color +
217
- `;font-size: 17px;text-transform: uppercase;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width: 400px;padding-top: 0.5em;">
218
- ` +
219
- this.podcast.title +
220
- `
264
+ <td colspan="2" valign="top" style="line-height:24px;color: ${this.color};font-size: 17px;text-transform: uppercase;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width: 400px;padding-top: 0.5em;">
265
+ ${this.title}
221
266
  </td>
222
267
  </tr>
223
- ` +
224
- this.emissionName,
268
+ ${this.emissionName},${this.description}`
225
269
  ];
226
- if (this.podcast.description) {
227
- html.push(
228
- `<tr>
229
- <td colspan="2" valign="top" style="line-height:24px;font-size: 14px;max-width: 500px;">
230
- ` +
231
- this.podcast.description +
232
- `
233
- </td>
234
- </tr>`
235
- );
236
- }
237
270
  html.push(
238
- `
239
- </table>
271
+ `</table>
240
272
  <div style="font-family: Arial, sans-serif;font-size: 12px;line-height: 20px;background: #f3f3f3;vertical-align: middle;padding: 15px 10px;display: flex; align-items:center; flex-wrap:wrap">
241
- <a href="` +
242
- window.location.href +
243
- `" title="` +
244
- this.$t('Listen this episode') +
245
- `">
273
+ <a href="${this.shareUrl}">
246
274
  <img width="44" height="44" style="display: inline-block;vertical-align: middle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAAxElEQVRIie3WMWpCURBG4Q8FSRrtbC2SPhvICmzchVuwtXQLbsE2pVUIkjqQHVgqNmIj6EvxGHhFQAIvcxt/OPVhhrlzh3sKZ4MvTLLFVYNPvJYQB294LiGucMYSw2xxcMQcj9niYIsputni4BvjEuJgjZcS4goXrDDKFgcnLDDIFgd7zNDLFgfvTUHnL23ISJuV7iS3Ooarn1VxkeeUvkDSV2b6J3FQT+pDW8Jb4vRD4Kqe1Kf/Ev4mTj32PhQ6b+9pPT+XHgysHrPM6QAAAABJRU5ErkJggg=="/>
247
275
  </a>
248
- <a style="color: #000;text-decoration: none; margin-right:8px" href="` +
249
- window.location.href +
250
- `">` +
251
- this.$t('Listen this episode') +
252
- `</a>` + this.articleHtml + `
253
- </div>
254
- ` +
255
- this.participantsName
276
+ <a style="color: #000;text-decoration: none; margin-right:8px" href="${this.shareUrl}">${this.shareText}</a>
277
+ ${this.articleHtml}
278
+ </div>${this.participantsName}`
256
279
  );
257
280
  return html.join('');
258
281
  },
259
-
260
- date(): string {
261
- if (1970 !== moment(this.podcast.pubDate).year()){
262
- return moment(this.podcast.pubDate).format('D MMMM YYYY, HH[h]mm');
263
- }
264
- return '';
265
- },
266
- duration(): string {
267
- if (this.podcast.duration <= 1) return '';
268
- if (this.podcast.duration > 600000) {
269
- return humanizeDuration(this.podcast.duration, {
270
- language: this.$i18n.locale,
271
- largest: 1,
272
- round: true,
273
- });
274
- }
275
- return humanizeDuration(this.podcast.duration, {
276
- language: this.$i18n.locale,
277
- largest: 2,
278
- round: true,
279
- });
280
- },
281
282
  },
282
283
  created(){
283
- this.initColor();
284
+ this.initData();
284
285
  },
285
286
  methods: {
286
287
  closePopup(event: { preventDefault: () => void }): void {
@@ -302,11 +303,24 @@ export default defineComponent({
302
303
  afterCopy(): void{
303
304
  (this.$refs.snackbar as InstanceType<typeof SnackbarVue>).open(this.$t('Data in clipboard'));
304
305
  },
305
- initColor(): void {
306
+ async initData(): Promise<void> {
307
+ let attributes;
308
+ if(this.$store.state.organisation && this.$store.state.organisation.attributes && Object.keys(this.$store.state.organisation.attributes).length > 1){
309
+ attributes = this.$store.state.organisation.attributes;
310
+ }else{
311
+ attributes = await octopusApi.fetchData<{[key:string]:string}>(0, 'organisation/attributes/'+state.generalParameters.organisationId);
312
+ }
313
+ if (Object.prototype.hasOwnProperty.call(attributes,'podcastmakerUrl')) {
314
+ this.shareUrl = attributes.podcastmakerUrl + window.location.pathname+window.location.search;
315
+ }
306
316
  if(state.generalParameters.podcastmaker && state.generalParameters.podcastmakerColor){
307
317
  this.color = state.generalParameters.podcastmakerColor;
318
+ return;
308
319
  }
309
- }
320
+ if (Object.prototype.hasOwnProperty.call(attributes,'COLOR')) {
321
+ this.color = attributes.COLOR;
322
+ }
323
+ },
310
324
  },
311
325
  })
312
326
  </script>
@@ -319,9 +333,6 @@ export default defineComponent({
319
333
  height: 200px;
320
334
  padding: 1em;
321
335
  border-radius: 1em;
322
- &:focus {
323
- outline-width: 0;
324
- }
325
336
  }
326
337
 
327
338
  .modal-dialog {
@@ -11,6 +11,7 @@
11
11
  {{ $t('Share QR Code') }}
12
12
  </h5>
13
13
  <button
14
+ ref="focusElement"
14
15
  type="button"
15
16
  class="btn-close btn-close-white"
16
17
  title="Close"
@@ -45,6 +46,9 @@ export default defineComponent({
45
46
  urlPage: { default: undefined, type: String},
46
47
  },
47
48
  emits: ['close'],
49
+ mounted(){
50
+ (this.$refs.focusElement as HTMLElement)?.focus();
51
+ },
48
52
  methods:{
49
53
  closePopup(): void {
50
54
  this.$emit('close');
@@ -12,6 +12,7 @@
12
12
  {{ $t('Share the player') }}
13
13
  </h5>
14
14
  <button
15
+ ref="focusElement"
15
16
  type="button"
16
17
  class="btn-close btn-close-white"
17
18
  title="Close"
@@ -126,6 +127,9 @@ export default defineComponent({
126
127
  return [this.$t('Embed link'),this.$t('Embedly link')];
127
128
  }
128
129
  },
130
+ mounted(){
131
+ (this.$refs.focusElement as HTMLElement)?.focus();
132
+ },
129
133
  methods: {
130
134
  closePopup(event: { preventDefault: () => void }): void {
131
135
  event.preventDefault();
@@ -55,7 +55,7 @@ export const playerLive = defineComponent({
55
55
  if (!Hls.isSupported()) {
56
56
  reject('Hls is not supported ! ');
57
57
  }
58
- let hls = new Hls();
58
+ const hls = new Hls();
59
59
  /* if(this.$store.state.authentication.isAuthenticated && this.$store.state.oAuthParam.accessToken){
60
60
  hls = new Hls({xhrSetup:
61
61
  (xhr: XMLHttpRequest) => {
@@ -34,7 +34,7 @@
34
34
  :organisation-id="myOrganisationId"
35
35
  :is-education="isEducation"
36
36
  />
37
- <ShareButtons v-if="pageParameters.isShareButtons" />
37
+ <ShareButtons v-if="pageParameters.isShareButtons" :playlist="playlist" />
38
38
  </div>
39
39
  </div>
40
40
  <PodcastList :playlist="playlist" />
@@ -6,9 +6,9 @@
6
6
  to="/main/priv/edit/playlist"
7
7
  class="d-flex justify-content-center my-3"
8
8
  >
9
- <button class="btn btn-primary">
9
+ <div class="btn btn-primary">
10
10
  {{ $t('Create playlist') }}
11
- </button>
11
+ </div>
12
12
  </router-link>
13
13
  <ProductorSearch
14
14
  v-if="isProductorSearch"
Binary file