@mindedge/vuetify-player 0.3.0 → 0.4.0

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.
@@ -1,71 +1,153 @@
1
1
  <template>
2
- <v-card>
3
- <v-card-actions class="justify-end">
4
- <v-tooltip top>
5
- <template v-slot:activator="{ on, attrs }">
6
- <v-btn
7
- color="primary"
8
- text
9
- v-bind="attrs"
10
- v-on="on"
11
- @click="onClickToggleParagraphView"
2
+ <v-card v-if="visibleState">
3
+ <v-card-actions class="d-flex flex-wrap flex-row-reverse mb-0 pb-0">
4
+ <div class="d-flex ml-auto">
5
+ <v-tooltip v-if="!hideAutoscroll" top>
6
+ <template #activator="{ on, attrs }">
7
+ <div v-bind="attrs" v-on="on">
8
+ <v-switch
9
+ :input-value="autoscrollState"
10
+ color="primary"
11
+ text
12
+ class="d-flex align-self-center"
13
+ @click="onClickToggleAutoscroll"
14
+ >
15
+ <template #label>
16
+ <div v-if="autoscrollState">
17
+ <v-icon> mdi-lock-open-variant </v-icon>
18
+ <span class="sr-only">
19
+ {{
20
+ t(
21
+ language,
22
+ 'captions.autoscroll_enabled'
23
+ )
24
+ }}
25
+ </span>
26
+ </div>
27
+ <div v-else>
28
+ <v-icon>mdi-arrow-vertical-lock</v-icon>
29
+ <span class="sr-only">
30
+ {{
31
+ t(
32
+ language,
33
+ 'captions.autoscroll_disabled'
34
+ )
35
+ }}
36
+ </span>
37
+ </div>
38
+ </template>
39
+ </v-switch>
40
+ </div>
41
+ </template>
42
+ <span>{{
43
+ autoscrollState
44
+ ? t(language, 'captions.disable_autoscroll')
45
+ : t(language, 'captions.enable_autoscroll')
46
+ }}</span>
47
+ </v-tooltip>
48
+
49
+ <v-tooltip v-if="!hideParagraphView" top>
50
+ <template #activator="{ on, attrs }">
51
+ <v-btn
52
+ color="primary"
53
+ text
54
+ class="d-flex align-self-center"
55
+ v-bind="attrs"
56
+ v-on="on"
57
+ @click="onClickToggleParagraphView"
58
+ >
59
+ <v-icon>{{
60
+ paragraphViewState
61
+ ? 'mdi-closed-caption-outline'
62
+ : 'mdi-text-box-outline'
63
+ }}</v-icon>
64
+ <span class="sr-only">{{
65
+ paragraphViewState
66
+ ? t(language, 'captions.view_as_captions')
67
+ : t(language, 'captions.view_as_paragraph')
68
+ }}</span>
69
+ </v-btn></template
12
70
  >
13
- <v-icon>{{
14
- paragraphView
15
- ? 'mdi-closed-caption-outline'
16
- : 'mdi-text-box-outline'
17
- }}</v-icon>
18
- <span class="sr-only">{{
19
- paragraphView
20
- ? t(language, 'captions.view_as_captions')
21
- : t(language, 'captions.view_as_paragraph')
22
- }}</span>
23
- </v-btn></template
24
- >
25
- <span>{{
26
- paragraphView
27
- ? t(language, 'captions.view_as_captions')
28
- : t(language, 'captions.view_as_paragraph')
29
- }}</span>
30
- </v-tooltip>
31
- <v-tooltip top>
32
- <template v-slot:activator="{ on, attrs }">
33
- <v-btn
34
- color="primary"
35
- text
36
- v-bind="attrs"
37
- v-on="on"
38
- @click="onClickToggleExpand"
71
+ <span>{{
72
+ paragraphViewState
73
+ ? t(language, 'captions.view_as_captions')
74
+ : t(language, 'captions.view_as_paragraph')
75
+ }}</span>
76
+ </v-tooltip>
77
+
78
+ <v-tooltip v-if="!hideExpand" top>
79
+ <template #activator="{ on, attrs }">
80
+ <v-btn
81
+ color="primary"
82
+ text
83
+ class="d-flex align-self-center"
84
+ v-bind="attrs"
85
+ v-on="on"
86
+ @click="onClickToggleExpand"
87
+ >
88
+ <v-icon>{{
89
+ expandedState
90
+ ? 'mdi-arrow-collapse'
91
+ : 'mdi-arrow-expand'
92
+ }}</v-icon>
93
+ <span class="sr-only">{{
94
+ expandedState
95
+ ? t(language, 'captions.collapse')
96
+ : t(language, 'captions.expand')
97
+ }}</span>
98
+ </v-btn></template
99
+ >
100
+ <span>{{
101
+ expandedState
102
+ ? t(language, 'captions.collapse')
103
+ : t(language, 'captions.expand')
104
+ }}</span>
105
+ </v-tooltip>
106
+
107
+ <v-tooltip v-if="!hideClose" top>
108
+ <template #activator="{ on, attrs }">
109
+ <v-btn
110
+ color="primary"
111
+ text
112
+ class="d-flex align-self-center"
113
+ v-bind="attrs"
114
+ v-on="on"
115
+ @click="onClickClose"
116
+ >
117
+ <v-icon>mdi-close</v-icon>
118
+ </v-btn></template
39
119
  >
40
- <v-icon>{{
41
- expanded ? 'mdi-arrow-collapse' : 'mdi-arrow-expand'
42
- }}</v-icon>
43
- <span class="sr-only">{{
44
- expanded
45
- ? t(language, 'captions.collapse')
46
- : t(language, 'captions.expand')
47
- }}</span>
48
- </v-btn></template
120
+ <span>{{ t(language, 'captions.close') }}</span>
121
+ </v-tooltip>
122
+ </div>
123
+
124
+ <div class="d-flex flex-grow-1">
125
+ <v-text-field
126
+ id="captions-search"
127
+ v-model="search"
128
+ :label="t(language, 'captions.search')"
129
+ append-icon="mdi-magnify"
130
+ class="ml-2 mr-12"
131
+ clearable
49
132
  >
50
- <span>{{
51
- expanded
52
- ? t(language, 'captions.collapse')
53
- : t(language, 'captions.expand')
54
- }}</span>
55
- </v-tooltip>
133
+ </v-text-field>
134
+ </div>
56
135
  </v-card-actions>
57
- <v-card-text>
136
+ <v-card-text class="mt-0 pt-0">
137
+ <span v-if="search && !filteredCues.length" class="caption">
138
+ {{ t(language, 'captions.none_found', [search]) }}
139
+ </span>
58
140
  <v-list ref="captionList" :class="captionsList">
59
141
  <v-list-item-group v-model="captionIndex">
60
142
  <v-list-item
61
143
  ref="captionItems"
62
- v-for="(cue, index) in cues"
144
+ v-for="(cue, index) in filteredCues"
63
145
  :key="index"
64
- :two-line="expanded"
146
+ :two-line="expandedState"
65
147
  @click="onCueClick(cue.startTime)"
66
148
  >
67
- <template v-if="!expanded">
68
- <v-list-item-icon v-if="!paragraphView">
149
+ <template v-if="!expandedState">
150
+ <v-list-item-icon v-if="!paragraphViewState">
69
151
  <v-icon
70
152
  >{{
71
153
  index === captionIndex
@@ -80,7 +162,7 @@
80
162
  class="caption-text"
81
163
  ></v-list-item-title>
82
164
  </v-list-item-content>
83
- <v-list-item-action v-if="!paragraphView">
165
+ <v-list-item-action v-if="!paragraphViewState">
84
166
  <span aria-hidden="true">
85
167
  {{
86
168
  filters.playerShortDuration(
@@ -94,13 +176,15 @@
94
176
  </span>
95
177
  </v-list-item-action>
96
178
  </template>
97
- <template v-if="expanded">
179
+ <template v-if="expandedState">
98
180
  <v-list-item-content>
99
181
  <v-list-item-title
100
182
  v-html="cue.rawText || cue.text"
101
183
  class="caption-text"
102
184
  ></v-list-item-title>
103
- <v-list-item-subtitle v-if="!paragraphView">
185
+ <v-list-item-subtitle
186
+ v-if="!paragraphViewState"
187
+ >
104
188
  <v-icon
105
189
  >{{
106
190
  index === captionIndex
@@ -139,10 +223,42 @@ export default {
139
223
  props: {
140
224
  value: { type: [Object, Array], required: true },
141
225
  language: { type: String, required: false, default: 'en-US' },
226
+ expanded: { type: Boolean, required: false, default: undefined },
227
+ hideExpand: { type: Boolean, required: false, default: true },
228
+ paragraphView: { type: Boolean, required: false, default: undefined },
229
+ hideParagraphView: { type: Boolean, required: false, default: false },
230
+ autoscroll: { type: Boolean, required: false, default: undefined },
231
+ hideAutoscroll: { type: Boolean, required: false, default: false },
232
+ visible: { type: Boolean, required: false, default: undefined },
233
+ hideClose: { type: Boolean, required: false, default: false },
142
234
  },
235
+ emits: [
236
+ 'click:cue',
237
+ 'click:expand',
238
+ 'click:paragraph',
239
+ 'click:autoscroll',
240
+ 'click:close',
241
+ 'update:expanded',
242
+ 'update:paragraph-view',
243
+ 'update:autoscroll',
244
+ 'update:visible',
245
+ ],
143
246
  computed: {
247
+ filteredCues() {
248
+ // Cues are an object with keys of 0,1,2,3...
249
+ const cues = Object.values(this.cues)
250
+ if (this.search !== '') {
251
+ return cues.filter((c) =>
252
+ c.text
253
+ .toLowerCase()
254
+ .includes((this.search || '').toLowerCase())
255
+ )
256
+ } else {
257
+ return cues
258
+ }
259
+ },
144
260
  captionsList() {
145
- return !this.expanded
261
+ return !this.expandedState
146
262
  ? 'captions-list captions-list--state-collapsed'
147
263
  : 'captions-list captions-list--state-expanded'
148
264
  },
@@ -150,12 +266,12 @@ export default {
150
266
  // Normal cues view
151
267
  if (
152
268
  typeof this.captions.cues !== 'undefined' &&
153
- !this.paragraphView
269
+ !this.paragraphViewState
154
270
  ) {
155
271
  return this.captions.cues
156
272
  } else if (
157
273
  typeof this.captions.cues !== 'undefined' &&
158
- this.paragraphView
274
+ this.paragraphViewState
159
275
  ) {
160
276
  // Paragraph view
161
277
  let cues = this.captions.cues
@@ -215,15 +331,70 @@ export default {
215
331
  return []
216
332
  }
217
333
  },
334
+ expandedState: {
335
+ get() {
336
+ if (typeof this.expanded !== 'undefined') {
337
+ return this.expanded
338
+ } else {
339
+ return this.localExpanded
340
+ }
341
+ },
342
+ set(v) {
343
+ this.localExpanded = v
344
+ this.$emit('update:expanded', v)
345
+ },
346
+ },
347
+ paragraphViewState: {
348
+ get() {
349
+ if (typeof this.paragraphView !== 'undefined') {
350
+ return this.paragraphView
351
+ } else {
352
+ return this.localParagraphView
353
+ }
354
+ },
355
+ set(v) {
356
+ this.$emit('update:paragraph-view', v)
357
+ this.localParagraphView = v
358
+ },
359
+ },
360
+ autoscrollState: {
361
+ get() {
362
+ if (typeof this.autoscroll !== 'undefined') {
363
+ return this.autoscroll
364
+ } else {
365
+ return this.localAutoscroll
366
+ }
367
+ },
368
+ set(v) {
369
+ this.$emit('update:autoscroll', v)
370
+ this.localAutoscroll = v
371
+ },
372
+ },
373
+ visibleState: {
374
+ get() {
375
+ if (typeof this.visible !== 'undefined') {
376
+ return this.visible
377
+ } else {
378
+ return this.localVisible
379
+ }
380
+ },
381
+ set(v) {
382
+ this.$emit('update:visible', v)
383
+ this.localVisible = v
384
+ },
385
+ },
218
386
  },
219
387
  data() {
220
388
  return {
221
389
  t,
222
390
  filters,
391
+ search: '',
223
392
  captions: {},
224
393
  captionIndex: 0,
225
- expanded: false,
226
- paragraphView: false,
394
+ localExpanded: false,
395
+ localParagraphView: false,
396
+ localAutoscroll: true,
397
+ localVisible: true,
227
398
  }
228
399
  },
229
400
  watch: {
@@ -235,6 +406,11 @@ export default {
235
406
  },
236
407
  },
237
408
  },
409
+
410
+ mounted() {
411
+ this.captions = this.value
412
+ this.captionIndex = this.currentCue(this.captions)
413
+ },
238
414
  methods: {
239
415
  currentCue(captions) {
240
416
  let currentIndex = 0
@@ -242,10 +418,13 @@ export default {
242
418
  if (
243
419
  typeof captions.cues !== 'undefined' &&
244
420
  typeof captions.activeCues !== 'undefined' &&
245
- captions.activeCues.length
421
+ captions.activeCues.length &&
422
+ this.filteredCues.length
246
423
  ) {
247
- for (let i = 0; i < captions.cues.length; i++) {
248
- const cue = captions.cues[i]
424
+ currentIndex = -1
425
+ // Loop over the filtered cues and see if we can find the index
426
+ for (let i = 0; i < this.filteredCues.length; i++) {
427
+ const cue = this.filteredCues[i]
249
428
  if (captions.activeCues[0].startTime === cue.startTime) {
250
429
  currentIndex = i
251
430
  }
@@ -258,6 +437,7 @@ export default {
258
437
  // If the captions ref and index is available and the list ref is available
259
438
  // Auto-scroll the list to the current caption
260
439
  if (
440
+ this.autoscrollState &&
261
441
  this.$refs.captionItems &&
262
442
  this.$refs.captionItems[currentIndex] &&
263
443
  this.$refs.captionItems[currentIndex].$el &&
@@ -274,17 +454,21 @@ export default {
274
454
  this.$emit('click:cue', time)
275
455
  },
276
456
  onClickToggleExpand() {
277
- this.expanded = !this.expanded
278
- this.$emit('click:expand', this.expanded)
457
+ this.expandedState = !this.expandedState
458
+ this.$emit('click:expand', this.expandedState)
279
459
  },
280
460
  onClickToggleParagraphView() {
281
- this.paragraphView = !this.paragraphView
282
- this.$emit('click:paragraph', this.paragraphView)
461
+ this.paragraphViewState = !this.paragraphViewState
462
+ this.$emit('click:paragraph-view', this.paragraphViewState)
463
+ },
464
+ onClickToggleAutoscroll() {
465
+ this.autoscrollState = !this.autoscrollState
466
+ this.$emit('click:autoscroll', !this.autoscroll)
467
+ },
468
+ onClickClose() {
469
+ this.visibleState = false
470
+ this.$emit('click:close')
283
471
  },
284
- },
285
- mounted() {
286
- this.captions = this.value
287
- this.captionIndex = this.currentCue(this.captions)
288
472
  },
289
473
  }
290
474
  </script>
@@ -294,28 +478,10 @@ export default {
294
478
  overflow-y: scroll;
295
479
  }
296
480
  .captions-list--state-collapsed {
297
- max-height: 10em;
298
- /* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
299
- mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
300
- linear-gradient(
301
- 0deg,
302
- rgba(0, 0, 0, 0) 0%,
303
- rgba(0, 0, 0, 1) 20%,
304
- rgba(0, 0, 0, 1) 80%,
305
- rgba(0, 0, 0, 0) 100%
306
- );
481
+ max-height: 15em;
307
482
  }
308
483
  .captions-list--state-expanded {
309
484
  aspect-ratio: 16 / 9;
310
- /* Fade the top/bottom 20% effect. The "red" mask is so the scrollbar doesn't get this effect*/
311
- mask: linear-gradient(90deg, rgba(255, 0, 0, 0) 98%, rgba(255, 0, 0, 1) 98%),
312
- linear-gradient(
313
- 0deg,
314
- rgba(0, 0, 0, 0) 0%,
315
- rgba(0, 0, 0, 1) 5%,
316
- rgba(0, 0, 0, 1) 95%,
317
- rgba(0, 0, 0, 0) 100%
318
- );
319
485
  }
320
486
  .caption-text {
321
487
  overflow: visible;