@windward/core 0.5.2 → 0.7.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.
- package/CHANGELOG.md +11 -0
- package/components/Content/Blocks/Accordion.vue +28 -0
- package/components/Content/Blocks/ClickableIcons.vue +31 -21
- package/components/Content/Blocks/Email.vue +11 -2
- package/components/Content/Blocks/FileDownload.vue +6 -8
- package/components/Content/Blocks/GenerateAIQuestionButton.vue +14 -6
- package/components/Content/Blocks/HorizontalRule.vue +1 -4
- package/components/Content/Blocks/ScenarioChoice.vue +58 -33
- package/components/Content/Blocks/Tab.vue +5 -0
- package/components/Content/Blocks/UserUpload.vue +1 -8
- package/components/Content/Blocks/Video.vue +96 -8
- package/components/Settings/AccordionSettings.vue +176 -136
- package/components/Settings/BlockQuoteSettings.vue +41 -2
- package/components/Settings/ClickableIconsSettings.vue +66 -10
- package/components/Settings/EmailSettings.vue +39 -4
- package/components/Settings/FileDownloadSettings.vue +38 -7
- package/components/Settings/HorizontalRuleSettings.vue +0 -3
- package/components/Settings/ScenarioChoiceSettings.vue +47 -9
- package/components/Settings/TabSettings.vue +124 -71
- package/components/Settings/TextEditorSettings.vue +14 -2
- package/components/Settings/UserUploadSettings.vue +42 -23
- package/components/Settings/VideoSettings/SourcePicker.vue +222 -0
- package/components/Settings/VideoSettings.vue +151 -165
- package/components/utils/TinyMCEWrapper.vue +25 -3
- package/components/utils/assets/tinymce/content/global.scss +14 -0
- package/components/utils/glossary/CourseGlossary.vue +52 -27
- package/helpers/tinymce/WindwardPlugins.ts +59 -10
- package/i18n/en-US/components/content/blocks/generate_questions.ts +2 -1
- package/i18n/en-US/components/content/blocks/video.ts +2 -51
- package/i18n/en-US/components/settings/accordion.ts +1 -0
- package/i18n/en-US/components/settings/tab.ts +1 -0
- package/i18n/en-US/components/settings/user_upload.ts +1 -0
- package/i18n/en-US/components/settings/video.ts +51 -0
- package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +9 -1
- package/i18n/en-US/shared/settings.ts +3 -0
- package/i18n/es-ES/components/content/blocks/generate_questions.ts +2 -1
- package/i18n/es-ES/components/content/blocks/video.ts +3 -53
- package/i18n/es-ES/components/settings/accordion.ts +1 -0
- package/i18n/es-ES/components/settings/tab.ts +2 -0
- package/i18n/es-ES/components/settings/user_upload.ts +1 -0
- package/i18n/es-ES/components/settings/video.ts +53 -0
- package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +9 -0
- package/i18n/es-ES/shared/settings.ts +3 -0
- package/i18n/sv-SE/components/content/blocks/generate_questions.ts +2 -1
- package/i18n/sv-SE/components/content/blocks/video.ts +2 -51
- package/i18n/sv-SE/components/settings/accordion.ts +2 -0
- package/i18n/sv-SE/components/settings/tab.ts +1 -0
- package/i18n/sv-SE/components/settings/user_upload.ts +1 -0
- package/i18n/sv-SE/components/settings/video.ts +51 -0
- package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +8 -0
- package/i18n/sv-SE/shared/settings.ts +3 -0
- package/package.json +2 -1
- package/plugin.js +1 -1
package/CHANGELOG.md
ADDED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
<v-container
|
|
4
|
+
class="pa-0"
|
|
5
|
+
v-if="
|
|
6
|
+
block.metadata.config.title ||
|
|
7
|
+
block.metadata.config.instructions
|
|
8
|
+
"
|
|
9
|
+
>
|
|
10
|
+
<h2>{{ block.metadata.config.title }}</h2>
|
|
11
|
+
|
|
12
|
+
<p>{{ block.metadata.config.instructions }}</p>
|
|
13
|
+
</v-container>
|
|
3
14
|
<v-expansion-panels
|
|
4
15
|
:value="selectedPanels"
|
|
5
16
|
flat
|
|
@@ -14,6 +25,8 @@
|
|
|
14
25
|
<v-expansion-panel-header
|
|
15
26
|
class="expansion-panel-header"
|
|
16
27
|
color="primary"
|
|
28
|
+
:ref="'expansion-panel-' + itemIndex"
|
|
29
|
+
@click="onOpenAccordion(itemIndex)"
|
|
17
30
|
>
|
|
18
31
|
{{
|
|
19
32
|
item.header === '' || item.header === null
|
|
@@ -89,6 +102,9 @@ export default {
|
|
|
89
102
|
if (_.isEmpty(this.block.metadata.config)) {
|
|
90
103
|
this.block.metadata.config = {}
|
|
91
104
|
}
|
|
105
|
+
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
106
|
+
this.block.metadata.config.title = ''
|
|
107
|
+
}
|
|
92
108
|
if (_.isEmpty(this.block.metadata.config.items)) {
|
|
93
109
|
const defaultObject = {
|
|
94
110
|
header: '',
|
|
@@ -157,6 +173,18 @@ export default {
|
|
|
157
173
|
}
|
|
158
174
|
},
|
|
159
175
|
methods: {
|
|
176
|
+
onOpenAccordion(value) {
|
|
177
|
+
const indexString = value.toString()
|
|
178
|
+
const referenceString = 'expansion-panel-' + indexString
|
|
179
|
+
if (
|
|
180
|
+
this.$refs[referenceString] &&
|
|
181
|
+
this.$refs[referenceString][0].$el
|
|
182
|
+
) {
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
this.$vuetify.goTo(this.$refs[referenceString][0].$el)
|
|
185
|
+
}, 300)
|
|
186
|
+
}
|
|
187
|
+
},
|
|
160
188
|
getImagePublicUrl(asset) {
|
|
161
189
|
const foundAsset = this.resolveAsset(asset)
|
|
162
190
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<v-container class="pa-0">
|
|
4
4
|
<h2>{{ block.metadata.config.title }}</h2>
|
|
5
5
|
|
|
6
|
-
<
|
|
6
|
+
<p>{{ block.metadata.config.description }}</p>
|
|
7
7
|
|
|
8
8
|
<p>
|
|
9
9
|
{{
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
>
|
|
24
24
|
<v-col cols="12" v-bind="iconColumnAttrs">
|
|
25
25
|
<button
|
|
26
|
+
class="mr-1"
|
|
26
27
|
:class="activatorButtonClass(itemIndex)"
|
|
27
28
|
@click="item.active = !item.active"
|
|
28
29
|
>
|
|
@@ -49,23 +50,24 @@
|
|
|
49
50
|
</button>
|
|
50
51
|
</v-col>
|
|
51
52
|
<v-col cols="12" v-bind="bodyColumnAttrs">
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
53
|
+
<v-container :class="bodyClass">
|
|
54
|
+
<h4
|
|
55
|
+
v-if="
|
|
56
|
+
block.metadata.config.display.show_title ||
|
|
57
|
+
item.active
|
|
58
|
+
"
|
|
59
|
+
role="button"
|
|
60
|
+
@click="item.active = !item.active"
|
|
61
|
+
>
|
|
62
|
+
{{ item.title }}
|
|
63
|
+
</h4>
|
|
64
|
+
<v-expand-transition>
|
|
65
|
+
<div v-if="item.active">
|
|
66
|
+
<v-divider light class="my-4" />
|
|
67
|
+
<TextViewer v-model="item.body"></TextViewer>
|
|
68
|
+
</div>
|
|
69
|
+
</v-expand-transition>
|
|
70
|
+
</v-container>
|
|
69
71
|
</v-col>
|
|
70
72
|
</v-row>
|
|
71
73
|
</v-container>
|
|
@@ -74,7 +76,6 @@
|
|
|
74
76
|
<script>
|
|
75
77
|
import _ from 'lodash'
|
|
76
78
|
import he from 'he'
|
|
77
|
-
import Uuid from '~/helpers/Uuid'
|
|
78
79
|
import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
79
80
|
import TextViewer from '~/components/Text/TextViewer'
|
|
80
81
|
|
|
@@ -114,7 +115,9 @@ export default {
|
|
|
114
115
|
}
|
|
115
116
|
},
|
|
116
117
|
data() {
|
|
117
|
-
return {
|
|
118
|
+
return {
|
|
119
|
+
saveState: false,
|
|
120
|
+
}
|
|
118
121
|
},
|
|
119
122
|
computed: {
|
|
120
123
|
decode() {
|
|
@@ -152,7 +155,7 @@ export default {
|
|
|
152
155
|
} else {
|
|
153
156
|
return {
|
|
154
157
|
xl: '2',
|
|
155
|
-
lg: '
|
|
158
|
+
lg: '3',
|
|
156
159
|
md: '3',
|
|
157
160
|
sm: '3',
|
|
158
161
|
}
|
|
@@ -237,6 +240,13 @@ export default {
|
|
|
237
240
|
}
|
|
238
241
|
}
|
|
239
242
|
},
|
|
243
|
+
bodyClass() {
|
|
244
|
+
if (window.innerWidth <= 665) {
|
|
245
|
+
return ''
|
|
246
|
+
} else {
|
|
247
|
+
return 'ml-4'
|
|
248
|
+
}
|
|
249
|
+
},
|
|
240
250
|
},
|
|
241
251
|
methods: {
|
|
242
252
|
isIcon(str) {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
class="pa-0 primary container-subject d-flex justify-center align-center"
|
|
26
26
|
>
|
|
27
27
|
<v-row class="d-flex ma-5">
|
|
28
|
-
<v-col cols="
|
|
28
|
+
<v-col cols="12">
|
|
29
29
|
{{
|
|
30
30
|
$t(
|
|
31
31
|
'windward.core.components.content.blocks.email.email'
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
}}
|
|
34
34
|
</v-col>
|
|
35
35
|
<v-col
|
|
36
|
+
v-if="false"
|
|
36
37
|
cols="6"
|
|
37
38
|
class="d-flex justify-end column-simulation"
|
|
38
39
|
>
|
|
@@ -170,7 +171,11 @@
|
|
|
170
171
|
>
|
|
171
172
|
<v-row class="pt-4">
|
|
172
173
|
<v-col cols="10" class="pa-0">
|
|
173
|
-
<v-btn
|
|
174
|
+
<v-btn
|
|
175
|
+
elevation="0"
|
|
176
|
+
color="primary"
|
|
177
|
+
text
|
|
178
|
+
>
|
|
174
179
|
<v-icon>mdi-reply</v-icon>
|
|
175
180
|
{{
|
|
176
181
|
$t(
|
|
@@ -197,6 +202,7 @@
|
|
|
197
202
|
</v-col>
|
|
198
203
|
<v-col cols="2" class="pa-0 d-flex justify-end">
|
|
199
204
|
<v-btn
|
|
205
|
+
v-show="false"
|
|
200
206
|
elevation="0"
|
|
201
207
|
color="primary"
|
|
202
208
|
outlined
|
|
@@ -350,4 +356,7 @@ export default {
|
|
|
350
356
|
.v-expansion-panels {
|
|
351
357
|
z-index: 0 !important;
|
|
352
358
|
}
|
|
359
|
+
.v-btn:before {
|
|
360
|
+
background-color: transparent !important;
|
|
361
|
+
}
|
|
353
362
|
</style>
|
|
@@ -8,17 +8,15 @@
|
|
|
8
8
|
)
|
|
9
9
|
}}
|
|
10
10
|
</h2>
|
|
11
|
-
<p
|
|
11
|
+
<p>
|
|
12
12
|
{{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
block.metadata.config.instructions
|
|
14
|
+
? block.metadata.config.instructions
|
|
15
|
+
: $t(
|
|
16
|
+
'windward.core.components.content.blocks.file_download.default_instructions'
|
|
17
|
+
)
|
|
16
18
|
}}
|
|
17
19
|
</p>
|
|
18
|
-
<TextViewer
|
|
19
|
-
v-if="block.metadata.config.instructions"
|
|
20
|
-
:value="block.metadata.config.instructions"
|
|
21
|
-
/>
|
|
22
20
|
<v-alert
|
|
23
21
|
v-if="
|
|
24
22
|
!block.metadata.config.items ||
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-btn
|
|
3
3
|
elevation="0"
|
|
4
|
-
color="
|
|
5
|
-
icon
|
|
4
|
+
color="secondary"
|
|
6
5
|
@click="generateAIQuestion"
|
|
7
6
|
:loading="isLoading"
|
|
8
7
|
:disabled="isLoading"
|
|
9
8
|
>
|
|
10
|
-
<v-icon v-if="!isLoading">mdi-magic-staff</v-icon>
|
|
9
|
+
<v-icon class="pr-1" v-if="!isLoading">mdi-magic-staff</v-icon>
|
|
10
|
+
{{
|
|
11
|
+
this.$t(
|
|
12
|
+
'windward.core.components.content.blocks.generate_questions.button_label'
|
|
13
|
+
)
|
|
14
|
+
}}
|
|
11
15
|
<template v-slot:loader>
|
|
12
16
|
<v-progress-circular indeterminate size="23"></v-progress-circular>
|
|
13
17
|
</template>
|
|
@@ -42,7 +46,7 @@ export default {
|
|
|
42
46
|
new Content(this.content),
|
|
43
47
|
new Assessment({ id: this.block.id }),
|
|
44
48
|
new AssessmentQuestion(),
|
|
45
|
-
|
|
49
|
+
`suggest/${this.questionType}`
|
|
46
50
|
).get()
|
|
47
51
|
|
|
48
52
|
if (response && response.length > 0) {
|
|
@@ -51,11 +55,15 @@ export default {
|
|
|
51
55
|
}
|
|
52
56
|
} catch (error) {
|
|
53
57
|
console.error(error)
|
|
54
|
-
this.$dialog.error(
|
|
58
|
+
this.$dialog.error(
|
|
59
|
+
this.$t(
|
|
60
|
+
'windward.core.components.content.blocks.generate_questions.error'
|
|
61
|
+
)
|
|
62
|
+
)
|
|
55
63
|
} finally {
|
|
56
64
|
this.isLoading = false
|
|
57
65
|
}
|
|
58
66
|
},
|
|
59
67
|
},
|
|
60
68
|
}
|
|
61
|
-
</script>
|
|
69
|
+
</script>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<hr :class="isDashed" />
|
|
3
|
+
<hr :class="isDashed" class="mt-2 mb-2" />
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
<script>
|
|
@@ -19,9 +19,6 @@ export default {
|
|
|
19
19
|
if (_.isEmpty(this.block.metadata.config)) {
|
|
20
20
|
this.block.metadata.config = {}
|
|
21
21
|
}
|
|
22
|
-
if (_.isEmpty(this.block.metadata.config)) {
|
|
23
|
-
this.block.metadata.config = {}
|
|
24
|
-
}
|
|
25
22
|
if (_.isEmpty(this.block.metadata.config.dashed)) {
|
|
26
23
|
this.block.metadata.config.dashed = false
|
|
27
24
|
}
|
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<v-container class="pa-0">
|
|
4
4
|
<h2>{{ block.metadata.config.title }}</h2>
|
|
5
|
-
<
|
|
6
|
-
<p>
|
|
7
|
-
{{
|
|
8
|
-
$t(
|
|
9
|
-
'windward.core.components.content.blocks.scenario_choice.information'
|
|
10
|
-
)
|
|
11
|
-
}}
|
|
12
|
-
</p>
|
|
5
|
+
<p>{{ block.metadata.config.description }}</p>
|
|
13
6
|
<div
|
|
14
7
|
v-if="choiceIndex !== null && block.metadata.config.show_reset"
|
|
15
8
|
class="text-right"
|
|
16
9
|
>
|
|
17
|
-
<v-btn
|
|
10
|
+
<v-btn
|
|
11
|
+
elevation="0"
|
|
12
|
+
color="primary"
|
|
13
|
+
outlined
|
|
14
|
+
@click="onClickReset"
|
|
15
|
+
>
|
|
18
16
|
{{
|
|
19
17
|
$t(
|
|
20
18
|
'windward.core.components.content.blocks.scenario_choice.try_again'
|
|
@@ -30,7 +28,7 @@
|
|
|
30
28
|
no-gutters
|
|
31
29
|
:class="rowClass(item, itemIndex)"
|
|
32
30
|
>
|
|
33
|
-
<v-col cols="
|
|
31
|
+
<v-col cols="12" v-bind="iconColumnAttrs" class="text-center">
|
|
34
32
|
<div
|
|
35
33
|
class="pt-8 pb-8 text-icon-container mb-4 mx-auto"
|
|
36
34
|
role="button"
|
|
@@ -48,30 +46,34 @@
|
|
|
48
46
|
}}
|
|
49
47
|
</strong>
|
|
50
48
|
</v-col>
|
|
51
|
-
<v-col cols="
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
<v-col cols="12" v-bind="bodyColumnAttrs">
|
|
50
|
+
<v-container :class="bodyClass">
|
|
51
|
+
<h4
|
|
52
|
+
role="button"
|
|
53
|
+
class="mt-4"
|
|
54
|
+
@click="onClickItem(itemIndex)"
|
|
55
|
+
>
|
|
56
|
+
{{ item.title }}
|
|
57
|
+
</h4>
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
59
|
+
<v-expand-transition>
|
|
60
|
+
<div v-if="choiceIndex !== null">
|
|
61
|
+
<v-divider light class="my-4" />
|
|
62
|
+
<TextViewer v-model="item.body"></TextViewer>
|
|
63
|
+
<a
|
|
64
|
+
v-if="linkedPage !== null"
|
|
65
|
+
class="white--text text-decoration-underline"
|
|
66
|
+
@click="
|
|
67
|
+
onClickLink(
|
|
68
|
+
linkedPage.course_content_id
|
|
69
|
+
)
|
|
70
|
+
"
|
|
71
|
+
>
|
|
72
|
+
{{ linkedPage.text }}
|
|
73
|
+
</a>
|
|
74
|
+
</div>
|
|
75
|
+
</v-expand-transition>
|
|
76
|
+
</v-container>
|
|
75
77
|
</v-col>
|
|
76
78
|
</v-row>
|
|
77
79
|
</v-container>
|
|
@@ -199,6 +201,29 @@ export default {
|
|
|
199
201
|
return null
|
|
200
202
|
}
|
|
201
203
|
},
|
|
204
|
+
iconColumnAttrs() {
|
|
205
|
+
return {
|
|
206
|
+
xl: '2',
|
|
207
|
+
lg: '3',
|
|
208
|
+
md: '3',
|
|
209
|
+
sm: '3',
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
bodyColumnAttrs() {
|
|
213
|
+
return {
|
|
214
|
+
xl: '10',
|
|
215
|
+
lg: '9',
|
|
216
|
+
md: '9',
|
|
217
|
+
sm: '9',
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
bodyClass() {
|
|
221
|
+
if (window.innerWidth <= 665) {
|
|
222
|
+
return ''
|
|
223
|
+
} else {
|
|
224
|
+
return 'ml-4'
|
|
225
|
+
}
|
|
226
|
+
},
|
|
202
227
|
},
|
|
203
228
|
beforeMount() {
|
|
204
229
|
// Apply the default config
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
+
<v-container class="pa-0">
|
|
4
|
+
<h2>{{ block.metadata.config.title }}</h2>
|
|
5
|
+
|
|
6
|
+
<p>{{ block.metadata.config.instructions }}</p>
|
|
7
|
+
</v-container>
|
|
3
8
|
<v-container class="pa-0">
|
|
4
9
|
<v-tabs dark v-model="block.metadata.config.currentTab" show-arrows>
|
|
5
10
|
<v-tabs-slider></v-tabs-slider>
|
|
@@ -6,14 +6,7 @@
|
|
|
6
6
|
</h2>
|
|
7
7
|
<v-row>
|
|
8
8
|
<v-col cols="12">
|
|
9
|
-
|
|
10
|
-
v-if="render || !block.__expandInstructions"
|
|
11
|
-
v-model="block.metadata.config.instructions"
|
|
12
|
-
></TextViewer>
|
|
13
|
-
<TextEditor
|
|
14
|
-
v-if="!render && block.__expandInstructions"
|
|
15
|
-
v-model="block.metadata.config.instructions"
|
|
16
|
-
/>
|
|
9
|
+
<p>{{ block.metadata.config.instructions }}</p>
|
|
17
10
|
</v-col>
|
|
18
11
|
<v-col v-if="!blockExists" cols="12">
|
|
19
12
|
<v-alert color="warning">
|
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
<v-icon class="mr-2">mdi-cloud-question</v-icon>
|
|
6
6
|
{{
|
|
7
7
|
$t(
|
|
8
|
-
'windward.core.components.content.blocks.video.
|
|
8
|
+
'windward.core.components.content.blocks.video.not_configured_title'
|
|
9
9
|
)
|
|
10
10
|
}}
|
|
11
11
|
</v-card-title>
|
|
12
12
|
<v-card-text>{{
|
|
13
|
-
$t(
|
|
14
|
-
'windward.core.components.content.blocks.video.video.edit_prompt'
|
|
15
|
-
)
|
|
13
|
+
$t('windward.core.components.content.blocks.video.edit_prompt')
|
|
16
14
|
}}</v-card-text>
|
|
17
15
|
</v-card>
|
|
18
16
|
|
|
@@ -60,6 +58,17 @@
|
|
|
60
58
|
"
|
|
61
59
|
:playbackrates="block.metadata.config.attributes.playbackrates"
|
|
62
60
|
/>
|
|
61
|
+
<!-- display first note in the playlist for now -->
|
|
62
|
+
<v-alert
|
|
63
|
+
v-if="notes.length > 0"
|
|
64
|
+
:color="
|
|
65
|
+
$vuetify.theme.isDark
|
|
66
|
+
? 'v-navigation-drawer'
|
|
67
|
+
: 'blue-grey lighten-5'
|
|
68
|
+
"
|
|
69
|
+
>
|
|
70
|
+
<TextViewer v-model="notes[0]"></TextViewer>
|
|
71
|
+
</v-alert>
|
|
63
72
|
</div>
|
|
64
73
|
</template>
|
|
65
74
|
|
|
@@ -67,10 +76,13 @@
|
|
|
67
76
|
import _ from 'lodash'
|
|
68
77
|
import VuetifyPlayer from '@mindedge/vuetify-player'
|
|
69
78
|
import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
79
|
+
import TextViewer from '~/components/Text/TextViewer'
|
|
80
|
+
import he from 'he'
|
|
70
81
|
|
|
71
82
|
export default {
|
|
72
83
|
name: 'ContentBlockVideo',
|
|
73
84
|
components: {
|
|
85
|
+
TextViewer,
|
|
74
86
|
VuetifyPlayer,
|
|
75
87
|
},
|
|
76
88
|
extends: BaseContentBlock,
|
|
@@ -96,12 +108,30 @@ export default {
|
|
|
96
108
|
)
|
|
97
109
|
return _.get(file, 'asset.public_url')
|
|
98
110
|
},
|
|
111
|
+
notes() {
|
|
112
|
+
const playlist = this.block.metadata.config.playlist
|
|
113
|
+
let result = []
|
|
114
|
+
for (const index in playlist) {
|
|
115
|
+
for (const sourceIndex in playlist[index].sources) {
|
|
116
|
+
let file = this.resolveAsset(
|
|
117
|
+
playlist[index].sources[sourceIndex]
|
|
118
|
+
)
|
|
119
|
+
if (
|
|
120
|
+
!_.isEmpty(_.get(file, 'asset.metadata.notes')) &&
|
|
121
|
+
//check the file notes are actually text and not an empty div
|
|
122
|
+
this.hasWords(_.get(file, 'asset.metadata.notes'))
|
|
123
|
+
) {
|
|
124
|
+
result.push(_.get(file, 'asset.metadata.notes'))
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return result
|
|
129
|
+
},
|
|
99
130
|
/**
|
|
100
131
|
* Resolve assets to their playlist items
|
|
101
132
|
*/
|
|
102
133
|
linkedPlaylist() {
|
|
103
134
|
const playlist = _.cloneDeep(this.block.metadata.config.playlist)
|
|
104
|
-
|
|
105
135
|
for (const index in playlist) {
|
|
106
136
|
for (const sourceIndex in playlist[index].sources) {
|
|
107
137
|
let file = this.resolveAsset(
|
|
@@ -112,6 +142,13 @@ export default {
|
|
|
112
142
|
src: _.get(file, 'asset.public_url', ''),
|
|
113
143
|
type: _.get(file, 'asset.metadata.mime', ''),
|
|
114
144
|
}
|
|
145
|
+
|
|
146
|
+
// If there's linked captions and there's no hard-set captions
|
|
147
|
+
// Fallback to the linked captions
|
|
148
|
+
const linkedCaptions = this.getLinkedCaptions(file)
|
|
149
|
+
if (playlist[index].tracks.length === 0 && linkedCaptions) {
|
|
150
|
+
playlist[index].tracks.push(linkedCaptions)
|
|
151
|
+
}
|
|
115
152
|
}
|
|
116
153
|
|
|
117
154
|
for (const trackIndex in playlist[index].tracks) {
|
|
@@ -126,7 +163,6 @@ export default {
|
|
|
126
163
|
default: true,
|
|
127
164
|
}
|
|
128
165
|
}
|
|
129
|
-
|
|
130
166
|
for (const adIndex in playlist[index].ads) {
|
|
131
167
|
for (const adSourceIndex in playlist[index].ads[adIndex]
|
|
132
168
|
.sources) {
|
|
@@ -138,7 +174,20 @@ export default {
|
|
|
138
174
|
src: _.get(file, 'asset.public_url', ''),
|
|
139
175
|
type: _.get(file, 'asset.metadata.mime', ''),
|
|
140
176
|
}
|
|
177
|
+
|
|
178
|
+
// If there's linked captions and there's no hard-set captions
|
|
179
|
+
// Fallback to the linked captions
|
|
180
|
+
const linkedCaptions = this.getLinkedCaptions(file)
|
|
181
|
+
if (
|
|
182
|
+
playlist[index].ads[adIndex].tracks.length === 0 &&
|
|
183
|
+
linkedCaptions
|
|
184
|
+
) {
|
|
185
|
+
playlist[index].ads[adIndex].tracks.push(
|
|
186
|
+
linkedCaptions
|
|
187
|
+
)
|
|
188
|
+
}
|
|
141
189
|
}
|
|
190
|
+
|
|
142
191
|
for (const adTrackIndex in playlist[index].ads[adIndex]
|
|
143
192
|
.tracks) {
|
|
144
193
|
let file = this.resolveAsset(
|
|
@@ -154,7 +203,11 @@ export default {
|
|
|
154
203
|
}
|
|
155
204
|
}
|
|
156
205
|
}
|
|
157
|
-
|
|
206
|
+
// reset adds to empty array as we aren't using these right now
|
|
207
|
+
// left code above in case we want to implement later
|
|
208
|
+
playlist.forEach((element) => {
|
|
209
|
+
element.ads = []
|
|
210
|
+
})
|
|
158
211
|
return playlist
|
|
159
212
|
},
|
|
160
213
|
},
|
|
@@ -249,11 +302,46 @@ export default {
|
|
|
249
302
|
this.$set(this.block, 'assets', [])
|
|
250
303
|
}
|
|
251
304
|
},
|
|
252
|
-
mounted() {},
|
|
253
305
|
methods: {
|
|
254
306
|
async onBeforeSave() {
|
|
255
307
|
this.block.body = 'video'
|
|
256
308
|
},
|
|
309
|
+
getLinkedCaptions(file) {
|
|
310
|
+
// Check to see if the video source has a linked asset and it's a vtt file
|
|
311
|
+
const linkedCaption = _.find(
|
|
312
|
+
_.get(file, 'asset.linked_assets', []),
|
|
313
|
+
function (f) {
|
|
314
|
+
return _.get(f, 'asset.metadata.extension', '') === 'vtt'
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if (linkedCaption) {
|
|
319
|
+
const foundAsset = this.block.assets.find((a) => {
|
|
320
|
+
return a.file_asset_id === linkedCaption.file_asset_id
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// The linked captions aren't part of the block.assets
|
|
324
|
+
// Add it so the block knows how to properly load it
|
|
325
|
+
if (!foundAsset) {
|
|
326
|
+
this.block.assets.push(_.cloneDeep(linkedCaption))
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return linkedCaption || null
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Check if the given text has words, omitting HTML tags and HTML entities
|
|
335
|
+
* @param {string} text - The text to check
|
|
336
|
+
* @returns {boolean} - True if the text has words, false otherwise
|
|
337
|
+
*/
|
|
338
|
+
hasWords(text) {
|
|
339
|
+
const strippedText = he
|
|
340
|
+
.decode(text)
|
|
341
|
+
.replace(/<\/?[^>]+(>|$)/g, '') // Remove HTML tags
|
|
342
|
+
.trim()
|
|
343
|
+
return /\b\w+\b/.test(strippedText) // Check if there are any words
|
|
344
|
+
},
|
|
257
345
|
},
|
|
258
346
|
}
|
|
259
347
|
</script>
|