@saooti/octopus-sdk 1.0.0 → 1.1.1

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 (317) hide show
  1. package/README.md +261 -0
  2. package/index.d.ts +4 -0
  3. package/index.ts +55 -3
  4. package/package.json +53 -45
  5. package/public/config.ts +4 -0
  6. package/public/css/fonts/icomoon.eot +0 -0
  7. package/public/css/fonts/icomoon.svg +129 -0
  8. package/public/css/fonts/icomoon.ttf +0 -0
  9. package/public/css/fonts/icomoon.woff +0 -0
  10. package/public/css/fonts/style.css +186 -1224
  11. package/public/img/403.jpeg +0 -0
  12. package/public/img/404.svg +242 -0
  13. package/public/img/ACPM.png +0 -0
  14. package/public/img/ouest_france_logo.svg +12 -0
  15. package/src/App.vue +102 -31
  16. package/src/api/classicCrud.ts +34 -0
  17. package/src/api/initialize.ts +5 -2
  18. package/src/assets/bootstrap-diff.scss +197 -0
  19. package/src/assets/form.scss +77 -77
  20. package/src/assets/general.scss +284 -272
  21. package/src/assets/live.scss +39 -0
  22. package/src/assets/modal.scss +43 -50
  23. package/src/assets/multiselect.scss +522 -573
  24. package/src/assets/octopus-library.scss +18 -4
  25. package/src/assets/share.scss +243 -0
  26. package/src/assets/transition.scss +98 -2
  27. package/src/components/display/aggregator/RssSection.vue +3 -5
  28. package/src/components/display/categories/CategoryChooser.vue +151 -114
  29. package/src/components/display/categories/CategoryFilter.vue +162 -0
  30. package/src/components/display/categories/CategoryList.vue +149 -117
  31. package/src/components/display/comments/AddCommentModal.vue +103 -108
  32. package/src/components/display/comments/CommentBasicView.vue +95 -0
  33. package/src/components/display/comments/CommentInput.vue +195 -183
  34. package/src/components/display/comments/CommentItem.vue +170 -208
  35. package/src/components/display/comments/CommentList.vue +134 -228
  36. package/src/components/display/comments/CommentParentInfo.vue +28 -62
  37. package/src/components/display/comments/CommentPlayer.vue +53 -56
  38. package/src/components/display/comments/CommentSection.vue +52 -83
  39. package/src/components/display/edit/EditBox.vue +10 -4
  40. package/src/components/display/edit/EditCommentBox.vue +124 -38
  41. package/src/components/display/emission/EmissionChooser.vue +88 -108
  42. package/src/components/display/emission/EmissionInlineList.vue +156 -157
  43. package/src/components/display/emission/EmissionItem.vue +72 -226
  44. package/src/components/display/emission/EmissionList.vue +159 -201
  45. package/src/components/display/emission/EmissionPlayerItem.vue +203 -174
  46. package/src/components/display/filter/AdvancedSearch.vue +224 -432
  47. package/src/components/display/filter/CategoryFilter.vue +105 -0
  48. package/src/components/display/filter/MonetizableFilter.vue +18 -15
  49. package/src/components/display/filter/ProductorSearch.vue +153 -176
  50. package/src/components/display/filter/RubriqueChoice.vue +97 -0
  51. package/src/components/display/filter/RubriqueFilter.vue +232 -0
  52. package/src/components/display/list/ListPaginate.vue +145 -0
  53. package/src/components/display/list/Paginate.vue +218 -0
  54. package/src/components/display/live/CountDown.vue +31 -30
  55. package/src/components/display/live/LiveHorizontalList.vue +84 -62
  56. package/src/components/display/live/LiveItem.vue +161 -186
  57. package/src/components/display/live/LiveList.vue +184 -295
  58. package/src/components/display/organisation/OrganisationChooser.vue +124 -162
  59. package/src/components/display/organisation/OrganisationChooserLight.vue +53 -56
  60. package/src/components/display/participant/ParticipantItem.vue +91 -128
  61. package/src/components/display/participant/ParticipantList.vue +134 -121
  62. package/src/components/display/playlist/PlaylistItem.vue +60 -97
  63. package/src/components/display/playlist/PlaylistList.vue +99 -92
  64. package/src/components/display/playlist/PodcastList.vue +117 -132
  65. package/src/components/display/playlist/PodcastPlaylistInlineList.vue +191 -0
  66. package/src/components/display/podcasts/AnimatorsItem.vue +29 -37
  67. package/src/components/display/podcasts/ParticipantDescription.vue +82 -0
  68. package/src/components/display/podcasts/PodcastFilterList.vue +49 -102
  69. package/src/components/display/podcasts/PodcastImage.vue +208 -225
  70. package/src/components/display/podcasts/PodcastInlineList.vue +62 -355
  71. package/src/components/display/podcasts/PodcastInlineListClassic.vue +240 -0
  72. package/src/components/display/podcasts/PodcastInlineListTemplate.vue +167 -0
  73. package/src/components/display/podcasts/PodcastItem.vue +94 -218
  74. package/src/components/display/podcasts/PodcastItemInfo.vue +166 -0
  75. package/src/components/display/podcasts/PodcastList.vue +127 -178
  76. package/src/components/display/podcasts/PodcastModuleBox.vue +234 -0
  77. package/src/components/display/podcasts/PodcastPlayBar.vue +101 -0
  78. package/src/components/display/podcasts/PodcastSwiperList.vue +204 -0
  79. package/src/components/display/podcasts/TagList.vue +60 -38
  80. package/src/components/display/rubriques/RubriqueChooser.vue +144 -131
  81. package/src/components/display/rubriques/RubriqueList.vue +216 -0
  82. package/src/components/display/sharing/PlayerParameters.vue +111 -153
  83. package/src/components/display/sharing/QrCode.vue +96 -0
  84. package/src/components/display/sharing/ShareButtons.vue +63 -233
  85. package/src/components/display/sharing/ShareButtonsIntern.vue +225 -0
  86. package/src/components/display/sharing/ShareDistribution.vue +102 -166
  87. package/src/components/display/sharing/SharePlayer.vue +189 -353
  88. package/src/components/display/sharing/SharePlayerColors.vue +78 -0
  89. package/src/components/display/sharing/SharePlayerTypes.vue +112 -0
  90. package/src/components/display/sharing/SplitButton.vue +42 -0
  91. package/src/components/display/sharing/SubscribeButtons.vue +65 -118
  92. package/src/components/display/studio/RecordingItemButton.vue +3 -5
  93. package/src/components/form/ClassicCheckbox.vue +66 -0
  94. package/src/components/form/ClassicLoading.vue +28 -0
  95. package/src/components/form/ClassicRadio.vue +66 -0
  96. package/src/components/form/ClassicSearch.vue +86 -0
  97. package/src/components/form/ClassicSelect.vue +65 -0
  98. package/src/components/misc/ErrorMessage.vue +27 -18
  99. package/src/components/misc/Footer.vue +151 -108
  100. package/src/components/misc/HomeDropdown.vue +95 -154
  101. package/src/components/misc/LeftMenu.vue +137 -206
  102. package/src/components/misc/Popover.vue +118 -0
  103. package/src/components/misc/Snackbar.vue +73 -37
  104. package/src/components/misc/TopBar.vue +211 -314
  105. package/src/components/misc/modal/ClipboardModal.vue +34 -47
  106. package/src/components/misc/modal/MessageModal.vue +74 -53
  107. package/src/components/misc/modal/NewsletterModal.vue +272 -224
  108. package/src/components/misc/modal/QrCodeModal.vue +58 -0
  109. package/src/components/misc/modal/ShareModalPlayer.vue +140 -74
  110. package/src/components/misc/player/Player.vue +146 -0
  111. package/src/components/misc/player/PlayerCompact.vue +154 -0
  112. package/src/components/misc/player/PlayerLarge.vue +166 -0
  113. package/src/components/misc/player/PlayerProgressBar.vue +112 -0
  114. package/src/components/misc/player/PlayerTimeline.vue +61 -0
  115. package/src/components/mixins/functions.ts +21 -18
  116. package/src/components/mixins/handle403.ts +17 -0
  117. package/src/components/mixins/init.ts +24 -0
  118. package/src/components/mixins/orgaComputed.ts +15 -0
  119. package/src/components/mixins/organisationFilter.ts +41 -0
  120. package/src/components/mixins/player/playerComment.ts +98 -0
  121. package/src/components/mixins/player/playerDisplay.ts +113 -0
  122. package/src/components/mixins/player/playerLive.ts +111 -0
  123. package/src/components/mixins/player/playerLogic.ts +225 -0
  124. package/src/components/mixins/tagOfMixins.ts +19 -0
  125. package/src/components/pages/Category.vue +24 -28
  126. package/src/components/pages/Emission.vue +144 -177
  127. package/src/components/pages/Emissions.vue +94 -110
  128. package/src/components/pages/Error403Page.vue +60 -0
  129. package/src/components/pages/Home.vue +74 -21
  130. package/src/components/pages/Lives.vue +53 -58
  131. package/src/components/pages/PageNotFound.vue +55 -0
  132. package/src/components/pages/Participant.vue +113 -129
  133. package/src/components/pages/Participants.vue +25 -41
  134. package/src/components/pages/Playlist.vue +86 -86
  135. package/src/components/pages/Playlists.vue +33 -52
  136. package/src/components/pages/Podcast.vue +206 -478
  137. package/src/components/pages/Podcasts.vue +112 -156
  138. package/src/components/pages/Rubrique.vue +21 -27
  139. package/src/components/pages/Search.vue +37 -94
  140. package/src/helper/dom.ts +2 -2
  141. package/src/helper/duration.ts +18 -8
  142. package/src/helper/useEventListener.ts +18 -0
  143. package/src/i18n.ts +36 -0
  144. package/src/locale/de.ts +309 -0
  145. package/src/locale/educationen.ts +14 -0
  146. package/src/locale/en.ts +316 -1
  147. package/src/locale/es.ts +309 -0
  148. package/src/locale/fr.ts +47 -15
  149. package/src/locale/it.ts +307 -0
  150. package/src/locale/messages.ts +11 -2
  151. package/src/locale/sl.ts +309 -0
  152. package/src/main.ts +64 -55
  153. package/src/router/router.ts +192 -159
  154. package/src/sass/_variables.scss +10 -8
  155. package/src/shims-tsx.d.ts +15 -0
  156. package/src/shims-vue-recaptcha-v3.d.ts +9 -0
  157. package/src/shims-vue.d.ts +5 -6
  158. package/src/store/AppStore.ts +41 -173
  159. package/src/store/class/adserver/adserverConfig.ts +9 -0
  160. package/src/store/class/adserver/adserverOtherEmission.ts +13 -0
  161. package/src/store/class/adserver/adserverTiming.ts +10 -0
  162. package/src/store/class/cartouchier/cartouche.ts +15 -0
  163. package/src/store/class/cartouchier/cartouchier.ts +9 -0
  164. package/src/store/class/conference/conference.ts +35 -0
  165. package/src/store/class/conference/conferenceMessage.ts +10 -0
  166. package/src/store/class/conference/conferenceParticipant.ts +18 -0
  167. package/src/store/class/conference/pad.ts +15 -0
  168. package/src/store/class/conference/studioCall.ts +7 -0
  169. package/src/store/class/contract/contract.ts +7 -0
  170. package/src/store/class/contract/contractOrganisation.ts +7 -0
  171. package/src/store/class/ftp/ftpEmission.ts +41 -0
  172. package/src/store/class/ftp/ftpParam.ts +12 -0
  173. package/src/store/class/ftp/testFtpEmission.ts +5 -0
  174. package/src/store/class/general/audioView.ts +21 -0
  175. package/src/store/class/general/category.ts +10 -0
  176. package/src/store/class/general/comment.ts +16 -0
  177. package/src/store/class/general/customPlayer.ts +9 -0
  178. package/src/store/class/general/emission.ts +23 -0
  179. package/src/store/class/general/fetchParam.ts +3 -0
  180. package/src/store/class/general/initState.ts +25 -0
  181. package/src/store/class/general/interfacePageable.ts +16 -0
  182. package/src/store/class/general/ituneCategory.ts +5 -0
  183. package/src/store/class/general/media.ts +14 -0
  184. package/src/store/class/general/organisation.ts +20 -0
  185. package/src/store/class/general/pageable.ts +13 -0
  186. package/src/store/class/general/participant.ts +12 -0
  187. package/src/store/class/general/player.ts +14 -0
  188. package/src/store/class/general/playlist.ts +13 -0
  189. package/src/store/class/general/podcast.ts +43 -0
  190. package/src/store/class/general/sortPageable.ts +5 -0
  191. package/src/store/class/general/soundcastCategory.ts +8 -0
  192. package/src/store/class/ouestFrance/ofTag.ts +36 -0
  193. package/src/store/class/ouestFrance/ofTagInfo.ts +9 -0
  194. package/src/store/class/ouestFrance/ofTagPage.ts +7 -0
  195. package/src/store/class/ouestFrance/ofTagSeo.ts +7 -0
  196. package/src/store/class/ouestFrance/ofTagVente.ts +6 -0
  197. package/src/store/class/ouestFrance/ofTagWithParents.ts +26 -0
  198. package/src/store/class/rss/aggregator.ts +28 -0
  199. package/src/store/class/rss/rssEmission.ts +14 -0
  200. package/src/store/class/rss/rssInfo.ts +8 -0
  201. package/src/store/class/rubrique/rubriquage.ts +10 -0
  202. package/src/store/class/rubrique/rubriquageFilter.ts +6 -0
  203. package/src/store/class/rubrique/rubrique.ts +9 -0
  204. package/src/store/class/stat/statArrayIncome.ts +6 -0
  205. package/src/store/class/stat/statArrayObject.ts +34 -0
  206. package/src/store/class/stat/statGraph.ts +7 -0
  207. package/src/store/class/user/person.ts +15 -0
  208. package/src/store/class/user/profile.ts +12 -0
  209. package/src/store/class/user/userKeycloak.ts +24 -0
  210. package/src/store/paramStore.ts +222 -217
  211. package/src/store/typeAppStore.ts +186 -235
  212. package/src/vuex-shim.d.ts +8 -0
  213. package/tsconfig.json +4 -0
  214. package/vue.config.js +16 -0
  215. package/public/css/fonts/saooti-ui.eot +0 -0
  216. package/public/css/fonts/saooti-ui.svg +0 -829
  217. package/public/css/fonts/saooti-ui.ttf +0 -0
  218. package/public/css/fonts/saooti-ui.woff +0 -0
  219. package/public/css/fonts/stitcher-logo.svg +0 -83
  220. package/public/img/ACPM.PNG +0 -0
  221. package/src/api/comments.ts +0 -7
  222. package/src/api/emissions.ts +0 -7
  223. package/src/api/podcasts.ts +0 -7
  224. package/src/api/profile.ts +0 -8
  225. package/src/api/studio.ts +0 -1
  226. package/src/assets/bootstrap_scss/_alert.scss +0 -51
  227. package/src/assets/bootstrap_scss/_badge.scss +0 -54
  228. package/src/assets/bootstrap_scss/_breadcrumb.scss +0 -42
  229. package/src/assets/bootstrap_scss/_button-group.scss +0 -164
  230. package/src/assets/bootstrap_scss/_buttons.scss +0 -291
  231. package/src/assets/bootstrap_scss/_card.scss +0 -278
  232. package/src/assets/bootstrap_scss/_carousel.scss +0 -197
  233. package/src/assets/bootstrap_scss/_close.scss +0 -41
  234. package/src/assets/bootstrap_scss/_code.scss +0 -48
  235. package/src/assets/bootstrap_scss/_custom-forms.scss +0 -522
  236. package/src/assets/bootstrap_scss/_dropdown.scss +0 -201
  237. package/src/assets/bootstrap_scss/_forms.scss +0 -352
  238. package/src/assets/bootstrap_scss/_functions.scss +0 -134
  239. package/src/assets/bootstrap_scss/_grid.scss +0 -69
  240. package/src/assets/bootstrap_scss/_images.scss +0 -42
  241. package/src/assets/bootstrap_scss/_input-group.scss +0 -191
  242. package/src/assets/bootstrap_scss/_jumbotron.scss +0 -17
  243. package/src/assets/bootstrap_scss/_list-group.scss +0 -158
  244. package/src/assets/bootstrap_scss/_media.scss +0 -8
  245. package/src/assets/bootstrap_scss/_mixins.scss +0 -47
  246. package/src/assets/bootstrap_scss/_modal.scss +0 -243
  247. package/src/assets/bootstrap_scss/_nav.scss +0 -120
  248. package/src/assets/bootstrap_scss/_navbar.scss +0 -324
  249. package/src/assets/bootstrap_scss/_pagination.scss +0 -74
  250. package/src/assets/bootstrap_scss/_popover.scss +0 -170
  251. package/src/assets/bootstrap_scss/_print.scss +0 -141
  252. package/src/assets/bootstrap_scss/_progress.scss +0 -46
  253. package/src/assets/bootstrap_scss/_reboot.scss +0 -482
  254. package/src/assets/bootstrap_scss/_root.scss +0 -20
  255. package/src/assets/bootstrap_scss/_spinners.scss +0 -55
  256. package/src/assets/bootstrap_scss/_tables.scss +0 -185
  257. package/src/assets/bootstrap_scss/_toasts.scss +0 -44
  258. package/src/assets/bootstrap_scss/_tooltip.scss +0 -115
  259. package/src/assets/bootstrap_scss/_transitions.scss +0 -20
  260. package/src/assets/bootstrap_scss/_type.scss +0 -125
  261. package/src/assets/bootstrap_scss/_utilities.scss +0 -17
  262. package/src/assets/bootstrap_scss/_variables.scss +0 -1145
  263. package/src/assets/bootstrap_scss/bootstrap-grid.scss +0 -29
  264. package/src/assets/bootstrap_scss/bootstrap-reboot.scss +0 -12
  265. package/src/assets/bootstrap_scss/bootstrap.scss +0 -44
  266. package/src/assets/bootstrap_scss/mixins/_alert.scss +0 -13
  267. package/src/assets/bootstrap_scss/mixins/_background-variant.scss +0 -22
  268. package/src/assets/bootstrap_scss/mixins/_badge.scss +0 -17
  269. package/src/assets/bootstrap_scss/mixins/_border-radius.scss +0 -63
  270. package/src/assets/bootstrap_scss/mixins/_box-shadow.scss +0 -20
  271. package/src/assets/bootstrap_scss/mixins/_breakpoints.scss +0 -123
  272. package/src/assets/bootstrap_scss/mixins/_buttons.scss +0 -110
  273. package/src/assets/bootstrap_scss/mixins/_caret.scss +0 -62
  274. package/src/assets/bootstrap_scss/mixins/_clearfix.scss +0 -7
  275. package/src/assets/bootstrap_scss/mixins/_deprecate.scss +0 -10
  276. package/src/assets/bootstrap_scss/mixins/_float.scss +0 -14
  277. package/src/assets/bootstrap_scss/mixins/_forms.scss +0 -177
  278. package/src/assets/bootstrap_scss/mixins/_gradients.scss +0 -45
  279. package/src/assets/bootstrap_scss/mixins/_grid-framework.scss +0 -71
  280. package/src/assets/bootstrap_scss/mixins/_grid.scss +0 -69
  281. package/src/assets/bootstrap_scss/mixins/_hover.scss +0 -37
  282. package/src/assets/bootstrap_scss/mixins/_image.scss +0 -36
  283. package/src/assets/bootstrap_scss/mixins/_list-group.scss +0 -21
  284. package/src/assets/bootstrap_scss/mixins/_lists.scss +0 -7
  285. package/src/assets/bootstrap_scss/mixins/_nav-divider.scss +0 -11
  286. package/src/assets/bootstrap_scss/mixins/_pagination.scss +0 -22
  287. package/src/assets/bootstrap_scss/mixins/_reset-text.scss +0 -17
  288. package/src/assets/bootstrap_scss/mixins/_resize.scss +0 -6
  289. package/src/assets/bootstrap_scss/mixins/_screen-reader.scss +0 -34
  290. package/src/assets/bootstrap_scss/mixins/_size.scss +0 -7
  291. package/src/assets/bootstrap_scss/mixins/_table-row.scss +0 -39
  292. package/src/assets/bootstrap_scss/mixins/_text-emphasis.scss +0 -17
  293. package/src/assets/bootstrap_scss/mixins/_text-hide.scss +0 -11
  294. package/src/assets/bootstrap_scss/mixins/_text-truncate.scss +0 -8
  295. package/src/assets/bootstrap_scss/mixins/_transition.scss +0 -16
  296. package/src/assets/bootstrap_scss/mixins/_visibility.scss +0 -8
  297. package/src/assets/bootstrap_scss/utilities/_align.scss +0 -8
  298. package/src/assets/bootstrap_scss/utilities/_background.scss +0 -19
  299. package/src/assets/bootstrap_scss/utilities/_borders.scss +0 -75
  300. package/src/assets/bootstrap_scss/utilities/_clearfix.scss +0 -3
  301. package/src/assets/bootstrap_scss/utilities/_display.scss +0 -26
  302. package/src/assets/bootstrap_scss/utilities/_embed.scss +0 -39
  303. package/src/assets/bootstrap_scss/utilities/_flex.scss +0 -51
  304. package/src/assets/bootstrap_scss/utilities/_float.scss +0 -11
  305. package/src/assets/bootstrap_scss/utilities/_overflow.scss +0 -5
  306. package/src/assets/bootstrap_scss/utilities/_position.scss +0 -32
  307. package/src/assets/bootstrap_scss/utilities/_screenreaders.scss +0 -11
  308. package/src/assets/bootstrap_scss/utilities/_shadows.scss +0 -6
  309. package/src/assets/bootstrap_scss/utilities/_sizing.scss +0 -20
  310. package/src/assets/bootstrap_scss/utilities/_spacing.scss +0 -73
  311. package/src/assets/bootstrap_scss/utilities/_stretched-link.scss +0 -19
  312. package/src/assets/bootstrap_scss/utilities/_text.scss +0 -72
  313. package/src/assets/bootstrap_scss/utilities/_visibility.scss +0 -13
  314. package/src/assets/bootstrap_scss/vendor/_rfs.scss +0 -204
  315. package/src/components/misc/Player.vue +0 -792
  316. package/src/shims-vuex.d.ts +0 -7
  317. package/src/views/Home.vue +0 -18
@@ -0,0 +1,232 @@
1
+ <template>
2
+ <div
3
+ v-if="organisationId && rubriquageData"
4
+ class="d-flex mt-3 align-items-center"
5
+ >
6
+ <ClassicCheckbox
7
+ v-model:textInit="isRubriquage"
8
+ class="flex-shrink-0"
9
+ id-checkbox="search-rubriquage-checkbox"
10
+ :label="$t('By topic')"
11
+ />
12
+ <div
13
+ v-if="isRubriquage"
14
+ class="d-flex flex-column mb-2"
15
+ >
16
+ <RubriqueChoice
17
+ v-for="(filter, index) in arrayFilter"
18
+ :key="index"
19
+ :index="index"
20
+ class="mb-2"
21
+ :rubriquage-display="getRubriquage(index)"
22
+ :rubrique-id-selected="filter.rubriqueId"
23
+ :rubriquage-id-selected="filter.rubriquageId"
24
+ @updateRubrique="updateRubrique"
25
+ @updateRubriquage="updateRubriquage"
26
+ @deleteRubriqueChoice="deleteRubriqueChoice(index)"
27
+ />
28
+ <button
29
+ v-if="availableRubriquage.length"
30
+ class="btn mt-2"
31
+ @click="addFilter"
32
+ >
33
+ {{ $t('Add a sort criterion by topic') }}
34
+ </button>
35
+ </div>
36
+ </div>
37
+ </template>
38
+
39
+ <script lang="ts">
40
+ import octopusApi from '@saooti/octopus-api';
41
+ import ClassicCheckbox from '../../form/ClassicCheckbox.vue';
42
+ import { Rubriquage } from '@/store/class/rubrique/rubriquage';
43
+ import { RubriquageFilter } from '@/store/class/rubrique/rubriquageFilter';
44
+ import { defineComponent, defineAsyncComponent } from 'vue';
45
+ const RubriqueChoice = defineAsyncComponent(() => import('./RubriqueChoice.vue'));
46
+ export default defineComponent({
47
+ components: {
48
+ RubriqueChoice,
49
+ ClassicCheckbox
50
+ },
51
+ props: {
52
+ organisationId: { default: undefined, type: String},
53
+ resetRubriquage: { default: false, type: Boolean},
54
+ },
55
+ emits: ['updateRubriquageFilter'],
56
+
57
+ data() {
58
+ return {
59
+ isRubriquage: false as boolean,
60
+ rubriquageId: [] as Array<number>,
61
+ rubriqueId: [] as Array<number>,
62
+ arrayFilter: [] as Array<RubriquageFilter>,
63
+ rubriquageData: [] as Array<Rubriquage>,
64
+ saveOrganisation: "" as string,
65
+ isInit: true as boolean,
66
+ isInternChanged: false as boolean,
67
+ };
68
+ },
69
+
70
+ computed: {
71
+ filterOrga(): string {
72
+ return this.$store.state.filter.organisationId;
73
+ },
74
+ organisation(): string|undefined {
75
+ return this.organisationId ?? this.filterOrga;
76
+ },
77
+ rubriqueFilter(): Array<RubriquageFilter>{
78
+ return this.$store.state.filter.rubriqueFilter;
79
+ },
80
+ availableRubriquage(): Array<Rubriquage>{
81
+ if(this.arrayFilter.length){
82
+ const rubriquageIdToNotShow = this.arrayFilter.map(a => a.rubriquageId);
83
+ return this.rubriquageData.filter((element)=>{
84
+ if(element.rubriquageId){
85
+ return !rubriquageIdToNotShow.includes(element.rubriquageId);
86
+ }
87
+ });
88
+ }
89
+ return this.rubriquageData;
90
+ }
91
+ },
92
+ watch: {
93
+ organisation(): void {
94
+ if(this.isRubriquage){
95
+ this.fetchTopics(true);
96
+ }
97
+ },
98
+ isRubriquage(): void {
99
+ if(this.isInternChanged ||this.isInit){
100
+ return;
101
+ }
102
+ this.isInternChanged = true;
103
+ if(0===this.arrayFilter.length && this.availableRubriquage[0].rubriquageId){
104
+ this.arrayFilter.push({rubriquageId: this.availableRubriquage[0].rubriquageId, rubriqueId: 0, nameRubriquage:this.rubriquageData[0].title, nameRubrique:""});
105
+ }
106
+ if(this.isRubriquage){
107
+ if(this.saveOrganisation !== this.organisation){
108
+ this.fetchTopics(true);
109
+ }
110
+ this.$emit('updateRubriquageFilter', this.arrayFilter);
111
+ }else{
112
+ this.$emit('updateRubriquageFilter', []);
113
+ }
114
+ this.resetRubriqueFilter();
115
+ this.$nextTick(() => {
116
+ this.isInternChanged = false;
117
+ });
118
+ },
119
+ arrayFilter:{
120
+ deep: true,
121
+ handler(){
122
+ if(this.isInternChanged ||this.isInit){
123
+ return;
124
+ }
125
+ this.isInternChanged = true;
126
+ this.resetRubriqueFilter();
127
+ if(this.isRubriquage){
128
+ this.$emit('updateRubriquageFilter', this.arrayFilter);
129
+ }
130
+ this.$nextTick(() => {
131
+ this.isInternChanged = false;
132
+ });
133
+ }
134
+ },
135
+ rubriqueFilter:{
136
+ deep: true,
137
+ async handler(){
138
+ if(this.isInternChanged){
139
+ return;
140
+ }
141
+ this.isInternChanged = true;
142
+ if(this.saveOrganisation !== this.filterOrga){
143
+ await this.fetchTopics(false);
144
+ }
145
+ if(this.rubriqueFilter.length){
146
+ this.arrayFilter = Array.from(this.rubriqueFilter);
147
+ this.isRubriquage = true;
148
+ }else if(this.rubriquageData[0].rubriquageId){
149
+ this.arrayFilter = [{rubriquageId: this.rubriquageData[0].rubriquageId, rubriqueId: 0, nameRubriquage:this.rubriquageData[0].title, nameRubrique:""}];
150
+ this.isRubriquage = false;
151
+ }
152
+ this.$emit('updateRubriquageFilter',this.isRubriquage? this.arrayFilter : []);
153
+ this.$nextTick(() => {
154
+ this.isInternChanged = false;
155
+ });
156
+ }
157
+ },
158
+ resetRubriquage(): void {
159
+ this.isRubriquage = false;
160
+ },
161
+ },
162
+
163
+ created() {
164
+ if(this.rubriqueFilter.length){
165
+ this.arrayFilter = Array.from(this.rubriqueFilter);
166
+ this.isRubriquage = true;
167
+ }
168
+ this.fetchTopics(false);
169
+ this.$nextTick(() => {
170
+ this.isInit = false;
171
+ });
172
+ },
173
+ methods: {
174
+ deleteRubriqueChoice(index: number): void{
175
+ this.arrayFilter.splice(index,1);
176
+ },
177
+ getRubriquage(index: number){
178
+ const elementToNotShow = Array.from(this.arrayFilter);
179
+ elementToNotShow.splice(index, 1);
180
+ if(elementToNotShow.length){
181
+ const rubriquageIdToNotShow = elementToNotShow.map(a => a.rubriquageId);
182
+ return this.rubriquageData.filter((element)=>{
183
+ if(element.rubriquageId){
184
+ return !rubriquageIdToNotShow.includes(element.rubriquageId);
185
+ }
186
+ });
187
+ }
188
+ return this.rubriquageData;
189
+ },
190
+ addFilter(): void{
191
+ if(this.availableRubriquage[0].rubriquageId){
192
+ this.arrayFilter.push({rubriquageId: this.availableRubriquage[0].rubriquageId, rubriqueId: 0,nameRubriquage:this.rubriquageData[0].title, nameRubrique:""});
193
+ }
194
+ },
195
+ updateRubrique(newValue: {rubriqueId: number; index: number}): void{
196
+ const item = this.arrayFilter[newValue.index];
197
+ item.rubriqueId = newValue.rubriqueId;
198
+ this.arrayFilter.splice(newValue.index, 1, item);
199
+ },
200
+ updateRubriquage(newValue: {rubriquageId: number; index: number}): void{
201
+ const item = this.arrayFilter[newValue.index];
202
+ item.rubriquageId = newValue.rubriquageId;
203
+ this.arrayFilter.splice(newValue.index, 1, item);
204
+ },
205
+ async fetchTopics(initArrayFilter: boolean): Promise<void> {
206
+ if(initArrayFilter){
207
+ this.arrayFilter.length = 0;
208
+ }
209
+ if (!this.organisation) return;
210
+ const data = await octopusApi.fetchDataWithParams<Array<Rubriquage>>(0, 'rubriquage/find/'+this.organisation,{}, true);
211
+ this.rubriquageData = data.filter((element: Rubriquage)=>{
212
+ return element.rubriques.length;
213
+ });
214
+ this.saveOrganisation = this.organisation;
215
+ if (0 === this.rubriquageData.length) return;
216
+ if(initArrayFilter && this.rubriquageData[0].rubriquageId){
217
+ this.arrayFilter.push({rubriquageId: this.rubriquageData[0].rubriquageId, rubriqueId: 0, nameRubriquage:this.rubriquageData[0].title, nameRubrique:""});
218
+ }
219
+ },
220
+ resetRubriqueFilter(): void{
221
+ if(0===this.rubriqueFilter.length || this.isInit){
222
+ return;
223
+ }
224
+ const queries = this.$route.query;
225
+ if (queries.rubriquesId) {
226
+ this.$router.replace({ query: {...queries, ...{rubriquesId: undefined} } });
227
+ }
228
+ this.$store.commit('filterRubrique', []);
229
+ }
230
+ },
231
+ })
232
+ </script>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <div
3
+ :id="id"
4
+ class="d-flex flex-column align-items-center"
5
+ >
6
+ <ClassicLoading
7
+ :loading-text="loadingText"
8
+ :error-text="errorText"
9
+ />
10
+ <template v-if="!loading">
11
+ <div class="paginate-section mb-2 page-box">
12
+ <div class="text-secondary">
13
+ <template v-if="textCount && (windowWidth > 1300 || windowWidth<=960)">
14
+ {{ textCount }}
15
+ </template>
16
+ </div>
17
+ <Paginate
18
+ v-if="!isPhone"
19
+ :first="first"
20
+ :rows-per-page="rowsPerPage"
21
+ :total-count="totalCount"
22
+ :range-size="rangeSize"
23
+ @update:first="changeFirst"
24
+ @update:rowsPerPage="changeSize"
25
+ />
26
+ </div>
27
+ </template>
28
+ <slot name="list" />
29
+ <button
30
+ v-show="((first+rowsPerPage) < totalCount) && isPhone"
31
+ :disabled="loading"
32
+ class="btn"
33
+ :class="buttonPlus ? 'btn-primary align-self-center width-fit-content m-4' : 'btn-more'"
34
+ :title="$t('See more')"
35
+ @click="fetchMore"
36
+ >
37
+ <template v-if="buttonPlus">
38
+ {{ $t('See more') }}
39
+ </template>
40
+ <div
41
+ :class="buttonPlus?'ms-1':''"
42
+ class="saooti-more"
43
+ />
44
+ </button>
45
+ </div>
46
+ </template>
47
+
48
+ <script lang="ts">
49
+ import domHelper from '../../../helper/dom';
50
+ import ClassicLoading from '../../form/ClassicLoading.vue';
51
+ import { state } from '../../../store/paramStore';
52
+ import Paginate from './Paginate.vue';
53
+ import { defineComponent } from 'vue'
54
+ export default defineComponent({
55
+ name: 'ListPaginate',
56
+ components: {
57
+ Paginate,
58
+ ClassicLoading
59
+ },
60
+ props: {
61
+ first: { default: 0, type: Number},
62
+ rowsPerPage: { default: 30, type: Number},
63
+ totalCount: { default: 0, type: Number},
64
+ textCount: { default: undefined, type: String},
65
+ id: {default: '', type: String},
66
+ loadingText:{ default: undefined, type: String},
67
+ errorText:{ default: undefined, type: String},
68
+ loading: { default: false, type:Boolean},
69
+ isMobile: { default: false, type: Boolean}
70
+ },
71
+
72
+ emits: ['update:first', 'update:rowsPerPage', 'update:isMobile'],
73
+ data() {
74
+ return {
75
+ windowWidth: window.innerWidth as number,
76
+ };
77
+ },
78
+ computed:{
79
+ buttonPlus(): boolean {
80
+ return (state.generalParameters.buttonPlus as boolean);
81
+ },
82
+ isPhone(){
83
+ return 960 >= this.windowWidth;
84
+ },
85
+ rangeSize(){
86
+ return this.windowWidth > 1600 ? 3 : this.windowWidth > 1530 ? 2 : 1;
87
+ },
88
+ },
89
+ watch:{
90
+ isPhone:{
91
+ immediate:true,
92
+ handler(){
93
+ this.$emit('update:isMobile', this.isPhone);
94
+ }
95
+ }
96
+ },
97
+ mounted() {
98
+ this.$nextTick(() => {
99
+ window.addEventListener('resize', this.onResize);
100
+ })
101
+ },
102
+ beforeUnmount() {
103
+ window.removeEventListener('resize', this.onResize);
104
+ },
105
+ methods:{
106
+ onResize() {
107
+ this.windowWidth = window.innerWidth;
108
+ },
109
+ fetchMore(){
110
+ this.$emit('update:first', this.first + this.rowsPerPage);
111
+ },
112
+ changeFirst(firstValue: number){
113
+ this.scrollToTop();
114
+ this.$emit('update:first', firstValue);
115
+ },
116
+ changeSize(sizeValue: number){
117
+ this.scrollToTop();
118
+ this.$emit('update:rowsPerPage', sizeValue)
119
+ },
120
+ scrollToTop(){
121
+ const element = document.getElementById(this.id);
122
+ if(!element || element.getBoundingClientRect().top > 0){return;}
123
+ const y = element.getBoundingClientRect().top + window.pageYOffset - domHelper.convertRemToPixels(3.5);
124
+ window.scrollTo({top: y, behavior: 'smooth'});
125
+ }
126
+ }
127
+ })
128
+ </script>
129
+ <style lang="scss">
130
+ .octopus-app .page-box.paginate-section{
131
+ display: flex;
132
+ justify-content: space-between;
133
+ align-items: center;
134
+ width: 99vw;
135
+ position: sticky;
136
+ top: 3.5rem;
137
+ z-index: 9;
138
+ padding-bottom: 1rem;
139
+ padding-top: 1rem;
140
+ @media (max-width: 960px) {
141
+ position: initial;
142
+ justify-content:center;
143
+ }
144
+ }
145
+ </style>
@@ -0,0 +1,218 @@
1
+ <template>
2
+ <div
3
+ v-if="totalCount > 0"
4
+ class="paginate"
5
+ >
6
+ <div class="d-flex align-items-center justify-content-center">
7
+ <label for="rows-per-page-select">{{ $t('Items per page :') }}</label>
8
+ <select
9
+ id="rows-per-page-select"
10
+ v-model="rowsPerPageIntern"
11
+ class="c-hand p-1 mx-2"
12
+ >
13
+ <option
14
+ v-for="option in optionsRowsPerPage"
15
+ :key="option"
16
+ :value="option"
17
+ >
18
+ {{ option }}
19
+ </option>
20
+ </select>
21
+ <div class="mx-2">
22
+ {{ $t('Showing items number', {page: (page+1), totalPage: totalPage}) }}
23
+ </div>
24
+ <div class="d-flex flex-nowrap">
25
+ <button
26
+ v-for="paginateButton in buttonsLeft"
27
+ :key="paginateButton.title"
28
+ class="btn"
29
+ :title="paginateButton.title"
30
+ :disabled="paginateButton.disabled"
31
+ @click="paginateButton.action"
32
+ >
33
+ <svg
34
+ xmlns="http://www.w3.org/2000/svg"
35
+ width="16"
36
+ height="16"
37
+ fill="currentColor"
38
+ viewBox="0 0 16 16"
39
+ >
40
+ <path
41
+ fill-rule="evenodd"
42
+ :d="paginateButton.path"
43
+ />
44
+ </svg>
45
+ </button>
46
+ <div
47
+ v-for="pageNumber in pagination"
48
+ :key="pageNumber"
49
+ >
50
+ <span
51
+ v-if="null === pageNumber"
52
+ class="btn"
53
+ >
54
+ ...
55
+ </span>
56
+ <button
57
+ v-else
58
+ class="btn"
59
+ :class="{ 'active': page === (pageNumber-1) }"
60
+ @click="changeFirst((pageNumber-1)*rowsPerPageIntern)"
61
+ >
62
+ {{ pageNumber }}
63
+ </button>
64
+ </div>
65
+ <button
66
+ v-for="paginateButton in buttonsRight"
67
+ :key="paginateButton.title"
68
+ class="btn"
69
+ :title="paginateButton.title"
70
+ :disabled="paginateButton.disabled"
71
+ @click="paginateButton.action"
72
+ >
73
+ <svg
74
+ xmlns="http://www.w3.org/2000/svg"
75
+ width="16"
76
+ height="16"
77
+ fill="currentColor"
78
+ viewBox="0 0 16 16"
79
+ >
80
+ <path
81
+ fill-rule="evenodd"
82
+ :d="paginateButton.path"
83
+ />
84
+ </svg>
85
+ </button>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ </template>
90
+
91
+ <script lang="ts">
92
+ import { defineComponent } from 'vue';
93
+ export default defineComponent({
94
+ name: "Paginate",
95
+ components: {
96
+ },
97
+ props: {
98
+ totalCount: { default: 0, type: Number },
99
+ first: { default: 0, type: Number },
100
+ rowsPerPage:{ default:0, type:Number},
101
+ rangeSize:{default:1, type: Number}
102
+ },
103
+ emits:['update:first', 'update:rowsPerPage'],
104
+ data() {
105
+ return {
106
+ rowsPerPageIntern: 30 as number,
107
+ optionsRowsPerPage: [5, 10, 15, 20, 25 , 30, 50] as Array<number>,
108
+ };
109
+ },
110
+ computed:{
111
+ buttonsLeft(){
112
+ return [{
113
+ title: this.$t('Go to first page'), disabled: 0===this.first, action: ()=>{this.changeFirst(0)}, path:"M11.854 3.646a.5.5 0 0 1 0 .708L8.207 8l3.647 3.646a.5.5 0 0 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 0 1 .708 0zM4.5 1a.5.5 0 0 0-.5.5v13a.5.5 0 0 0 1 0v-13a.5.5 0 0 0-.5-.5z"},
114
+ {title: this.$t('Go to previous page'), disabled: 0===this.first, action: ()=>{this.changeFirst(this.first - this.rowsPerPage)}, path:"M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"},]
115
+ },
116
+ buttonsRight(){
117
+ return [
118
+ {title: this.$t('Go to next page'), disabled: this.lastFirst===this.first, action: ()=>{this.changeFirst(this.first + this.rowsPerPage)}, path:"M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"},
119
+ {title: this.$t('Go to last page'), disabled: this.lastFirst===this.first, action: ()=>{this.changeFirst(this.lastFirst)}, path:"M4.146 3.646a.5.5 0 0 0 0 .708L7.793 8l-3.647 3.646a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708 0zM11.5 1a.5.5 0 0 1 .5.5v13a.5.5 0 0 1-1 0v-13a.5.5 0 0 1 .5-.5z"}]
120
+ },
121
+ page(){
122
+ return Math.floor(this.first/this.rowsPerPage);
123
+ },
124
+ totalPage(){
125
+ return Math.ceil(this.totalCount/this.rowsPerPage);
126
+ },
127
+ pagination(): (number | null)[] {
128
+ if(-1===this.rangeSize){return[];}
129
+ const res = [];
130
+ const minPaginationElems = 5 + this.rangeSize * 2;
131
+ let rangeStart = this.totalPage <= minPaginationElems ? 1 : (this.page + 1) - this.rangeSize;
132
+ let rangeEnd =this.totalPage <= minPaginationElems ? this.totalPage : (this.page + 1)+ this.rangeSize;
133
+ rangeEnd = rangeEnd > this.totalPage ? this.totalPage : rangeEnd;
134
+ rangeStart = rangeStart < 1 ? 1 : rangeStart;
135
+ if (this.totalPage > minPaginationElems) {
136
+ const isStartBoundaryReached = rangeStart - 1 < 3;
137
+ const isEndBoundaryReached = this.totalPage - rangeEnd < 3;
138
+ if (isStartBoundaryReached) {
139
+ rangeEnd = minPaginationElems - 2;
140
+ for (let i = 1; i < rangeStart; i++) {
141
+ res.push(i);
142
+ }
143
+ } else {
144
+ res.push(1);
145
+ res.push(null);
146
+ }
147
+ if (isEndBoundaryReached) {
148
+ rangeStart = this.totalPage - (minPaginationElems - 3);
149
+ for (let i = rangeStart; i <= this.totalPage; i++) {
150
+ res.push(i);
151
+ }
152
+ } else {
153
+ for (let i = rangeStart; i <= rangeEnd; i++) {
154
+ res.push(i);
155
+ }
156
+ res.push(null);
157
+ res.push(this.totalPage);
158
+ }
159
+ } else {
160
+ for (let i = rangeStart; i <= rangeEnd; i++) {
161
+ res.push(i);
162
+ }
163
+ }
164
+ return res;
165
+ },
166
+ lastFirst(): number{
167
+ return (this.totalPage-1)*this.rowsPerPage;
168
+ }
169
+ },
170
+ watch: {
171
+ rowsPerPageIntern(){
172
+ if(this.rowsPerPage !== this.rowsPerPageIntern){
173
+ this.$emit('update:rowsPerPage', this.rowsPerPageIntern);
174
+ }
175
+ },
176
+ rowsPerPage(){
177
+ if(this.rowsPerPage !== this.rowsPerPageIntern){
178
+ this.rowsPerPageIntern =this.rowsPerPage;
179
+ }
180
+ }
181
+ },
182
+ created(){
183
+ this.initRowsPerPage();
184
+ },
185
+
186
+ methods:{
187
+ initRowsPerPage(){
188
+ if(!this.optionsRowsPerPage.includes(this.rowsPerPage)){
189
+ this.optionsRowsPerPage.push(this.rowsPerPage);
190
+ this.optionsRowsPerPage.sort((a,b)=>a-b);
191
+ }
192
+ this.rowsPerPageIntern = this.rowsPerPage;
193
+ },
194
+ changeFirst(newFirst: number){
195
+ this.$emit('update:first', newFirst);
196
+ },
197
+ }
198
+ });
199
+ </script>
200
+ <style lang="scss">
201
+ @import '../../../sass/_variables.scss';
202
+ .octopus-app .paginate{
203
+ display: flex;
204
+ justify-content: flex-end;
205
+ select{
206
+ border-top: 0;
207
+ border-right: 0;
208
+ border-left: 0;
209
+ background: transparent !important;
210
+ }
211
+ .btn{
212
+ border-radius: 0;
213
+ &.active{
214
+ background: rgba($octopus-primary-color, 0.3) ;
215
+ }
216
+ }
217
+ }
218
+ </style>
@@ -1,7 +1,9 @@
1
1
  <template>
2
2
  <div class="d-flex flex-column align-items-center text-danger">
3
3
  <h3>{{ $t('This live will start') }}</h3>
4
- <h3 ref="countdown" v-if="countdownTimer">
4
+ <h3
5
+ v-if="countdownTimer"
6
+ >
5
7
  {{
6
8
  $t('In days hours minutes seconds', {
7
9
  days: pad(days),
@@ -11,59 +13,58 @@
11
13
  })
12
14
  }}
13
15
  </h3>
14
- <h3 v-else>{{ $t('In a moment') }}</h3>
16
+ <h3 v-else>
17
+ {{ $t('In a moment') }}
18
+ </h3>
15
19
  </div>
16
20
  </template>
17
- <style lang="scss"></style>
21
+
18
22
  <script lang="ts">
19
23
  import { defineComponent } from 'vue'
20
24
  export default defineComponent({
21
- components: {},
22
-
25
+ props: {
26
+ timeRemaining: { default: undefined, type: Number},
27
+ },
28
+ data() {
29
+ return {
30
+ seconds: 0 as number,
31
+ countdownTimer: undefined as ReturnType<typeof setTimeout>|undefined,
32
+ days: 0 as number,
33
+ hours: 0 as number,
34
+ minutes: 0 as number,
35
+ remainingSeconds: 0 as number,
36
+ };
37
+ },
38
+ computed: {},
23
39
  mounted() {
24
40
  if (!this.timeRemaining || this.timeRemaining <= 0) return;
25
-
26
41
  this.seconds = this.timeRemaining;
27
42
  this.countdownTimer = setInterval(() => {
28
43
  this.timer();
29
44
  }, 1000);
30
45
  },
31
-
32
- props: ['timeRemaining'],
33
-
34
- data() {
35
- return {
36
- seconds: undefined as any,
37
- countdownTimer: undefined as any,
38
- days: 0,
39
- hours: 0,
40
- minutes: 0,
41
- remainingSeconds: 0,
42
- };
46
+ unmounted() {
47
+ clearInterval((this.countdownTimer as unknown as number));
43
48
  },
44
49
 
45
- computed: {},
46
-
47
50
  methods: {
48
- timer() {
51
+ timer(): void {
49
52
  this.days = Math.floor(this.seconds / 24 / 60 / 60);
50
- var hoursLeft = Math.floor(this.seconds - this.days * 86400);
53
+ const hoursLeft = Math.floor(this.seconds - this.days * 86400);
51
54
  this.hours = Math.floor(hoursLeft / 3600);
52
- var minutesLeft = Math.floor(hoursLeft - this.hours * 3600);
55
+ const minutesLeft = Math.floor(hoursLeft - this.hours * 3600);
53
56
  this.minutes = Math.floor(minutesLeft / 60);
54
57
  this.remainingSeconds = this.seconds % 60;
55
-
56
- /* this.$refs.countdown.innerHTML = this.pad(days) + ":" + this.pad(hours) + ":" + this.pad(minutes) + ":" + this.pad(remainingSeconds); */
57
58
  if (0 === this.seconds) {
58
- clearInterval(this.countdownTimer);
59
+ clearInterval((this.countdownTimer as unknown as number));
59
60
  this.countdownTimer = undefined;
60
61
  } else {
61
62
  this.seconds--;
62
63
  }
63
64
  },
64
- pad(n: string|number) {
65
- return n < 10 ? '0' + n : n;
65
+ pad(n: number): string {
66
+ return n < 10 ? '0' + n : n.toString();
66
67
  },
67
68
  },
68
- });
69
- </script>
69
+ })
70
+ </script>