@windward/core 0.15.0 → 0.17.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 +6 -0
- package/components/Content/Blocks/Accordion.vue +39 -38
- package/components/Content/Blocks/BlockQuote.vue +51 -47
- package/components/Content/Blocks/OpenResponse.vue +19 -7
- package/components/Navigation/Items/UserUploadNav.vue +35 -20
- package/components/Settings/TextEditorSettings.vue +1 -0
- package/components/utils/ContentViewer.vue +3 -0
- package/components/utils/FillInBlank/FillInBlankInput.vue +32 -28
- package/components/utils/GenerateAIQuestionButton.vue +345 -0
- package/components/utils/TinyMCEWrapper.vue +14 -57
- package/components/utils/glossary/CourseGlossary.vue +13 -8
- package/helpers/tinymce/WindwardPlugins.ts +36 -3
- package/i18n/en-US/components/content/blocks/generate_questions.ts +26 -11
- package/i18n/en-US/shared/content_blocks.ts +1 -1
- package/i18n/en-US/shared/settings.ts +1 -1
- package/i18n/es-ES/components/content/blocks/generate_questions.ts +11 -1
- package/i18n/es-ES/shared/content_blocks.ts +1 -1
- package/i18n/es-ES/shared/settings.ts +1 -2
- package/i18n/sv-SE/components/content/blocks/generate_questions.ts +11 -1
- package/i18n/sv-SE/shared/content_blocks.ts +1 -1
- package/i18n/sv-SE/shared/settings.ts +1 -1
- package/models/Activity.ts +9 -0
- package/package.json +1 -1
- package/pages/glossary.vue +30 -1
- package/pages/userUpload.vue +69 -46
- package/plugin.js +1 -1
- package/utils/index.js +1 -1
- package/components/Content/Blocks/GenerateAIQuestionButton.vue +0 -139
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<v-row class="container-generate-ai mt-2">
|
|
4
|
+
<v-col>{{
|
|
5
|
+
$t(
|
|
6
|
+
'windward.core.components.content.blocks.generate_questions.ai_assistance'
|
|
7
|
+
)
|
|
8
|
+
}}</v-col>
|
|
9
|
+
<v-col>
|
|
10
|
+
<v-select
|
|
11
|
+
v-model="selectedContent"
|
|
12
|
+
:items="flattenedContent"
|
|
13
|
+
class="btn-selector"
|
|
14
|
+
outlined
|
|
15
|
+
hide-details
|
|
16
|
+
dense
|
|
17
|
+
:label="
|
|
18
|
+
$t(
|
|
19
|
+
'windward.core.components.content.blocks.generate_questions.selected_pages'
|
|
20
|
+
)
|
|
21
|
+
"
|
|
22
|
+
item-text="content.name"
|
|
23
|
+
return-object
|
|
24
|
+
></v-select>
|
|
25
|
+
</v-col>
|
|
26
|
+
<v-col>
|
|
27
|
+
<v-select
|
|
28
|
+
v-model="selectedDifficulty"
|
|
29
|
+
:items="taxonomyLevels"
|
|
30
|
+
item-text="text"
|
|
31
|
+
class="btn-selector"
|
|
32
|
+
outlined
|
|
33
|
+
hide-details
|
|
34
|
+
dense
|
|
35
|
+
:label="
|
|
36
|
+
$t(
|
|
37
|
+
'windward.core.components.content.blocks.generate_questions.blooms.blooms_taxonomy'
|
|
38
|
+
)
|
|
39
|
+
"
|
|
40
|
+
return-object
|
|
41
|
+
></v-select>
|
|
42
|
+
</v-col>
|
|
43
|
+
<v-col
|
|
44
|
+
cols="auto"
|
|
45
|
+
class="d-flex align-center"
|
|
46
|
+
v-if="isFlashcardType"
|
|
47
|
+
>
|
|
48
|
+
<v-switch
|
|
49
|
+
v-model="replaceExisting"
|
|
50
|
+
hide-details
|
|
51
|
+
dense
|
|
52
|
+
color="secondary"
|
|
53
|
+
class="mt-0 pt-0"
|
|
54
|
+
:label="
|
|
55
|
+
$t(
|
|
56
|
+
'windward.games.components.settings.flashcard.form.replace_existing'
|
|
57
|
+
)
|
|
58
|
+
"
|
|
59
|
+
:disabled="isLoading"
|
|
60
|
+
></v-switch>
|
|
61
|
+
</v-col>
|
|
62
|
+
<v-col>
|
|
63
|
+
<v-btn
|
|
64
|
+
elevation="0"
|
|
65
|
+
color="secondary"
|
|
66
|
+
class="mb-1 btn-selector"
|
|
67
|
+
:loading="isLoading"
|
|
68
|
+
:disabled="isLoading"
|
|
69
|
+
@click="generateAIQuestion"
|
|
70
|
+
>
|
|
71
|
+
<v-icon v-if="!isLoading" class="pr-1"
|
|
72
|
+
>mdi-magic-staff</v-icon
|
|
73
|
+
>
|
|
74
|
+
{{
|
|
75
|
+
$t(
|
|
76
|
+
'windward.core.components.content.blocks.generate_questions.button_label'
|
|
77
|
+
)
|
|
78
|
+
}}
|
|
79
|
+
<template v-slot:loader>
|
|
80
|
+
<v-progress-circular
|
|
81
|
+
indeterminate
|
|
82
|
+
size="23"
|
|
83
|
+
></v-progress-circular>
|
|
84
|
+
</template>
|
|
85
|
+
</v-btn>
|
|
86
|
+
</v-col>
|
|
87
|
+
</v-row>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script>
|
|
92
|
+
import _ from 'lodash'
|
|
93
|
+
import { mapGetters } from 'vuex'
|
|
94
|
+
import AssessmentQuestion from '~/models/AssessmentQuestion'
|
|
95
|
+
import Course from '~/models/Course'
|
|
96
|
+
import Assessment from '~/models/Assessment'
|
|
97
|
+
import Content from '~/models/Content'
|
|
98
|
+
import Activity from '../../models/Activity'
|
|
99
|
+
|
|
100
|
+
export default {
|
|
101
|
+
name: 'GenerateAIQuestionButton',
|
|
102
|
+
props: {
|
|
103
|
+
course: { type: Object, required: true },
|
|
104
|
+
content: { type: Object, required: true },
|
|
105
|
+
block: { type: Object, required: true },
|
|
106
|
+
questionType: { type: String, required: true },
|
|
107
|
+
replaceExistingMode: { type: Boolean, default: false },
|
|
108
|
+
},
|
|
109
|
+
data() {
|
|
110
|
+
return {
|
|
111
|
+
isLoading: false,
|
|
112
|
+
selectedContent: '',
|
|
113
|
+
selectedDifficulty: {
|
|
114
|
+
value: 'None',
|
|
115
|
+
text: this.$t(
|
|
116
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
117
|
+
),
|
|
118
|
+
},
|
|
119
|
+
replaceExisting: this.replaceExistingMode,
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
computed: {
|
|
123
|
+
...mapGetters({
|
|
124
|
+
contentTree: 'content/getTree',
|
|
125
|
+
}),
|
|
126
|
+
isFlashcardType() {
|
|
127
|
+
return this.questionType === 'flashcard'
|
|
128
|
+
},
|
|
129
|
+
flattenedContent() {
|
|
130
|
+
let cloneContentTree = _.cloneDeep(this.contentTree)
|
|
131
|
+
const homepage = this.$ContentService.getHomepage()
|
|
132
|
+
if (!_.isEmpty(homepage)) {
|
|
133
|
+
cloneContentTree.unshift(homepage)
|
|
134
|
+
}
|
|
135
|
+
let fullTree = []
|
|
136
|
+
// flatten content tree to get nested children pages
|
|
137
|
+
cloneContentTree.forEach((content) => {
|
|
138
|
+
fullTree.push(content)
|
|
139
|
+
if (content.children.length > 0) {
|
|
140
|
+
fullTree = fullTree.concat(_.flatten(content.children))
|
|
141
|
+
// check if children have children
|
|
142
|
+
content.children.forEach((child) => {
|
|
143
|
+
fullTree = fullTree.concat(_.flatten(child.children))
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
//
|
|
148
|
+
if (_.isEmpty(this.selectedContent)) {
|
|
149
|
+
// returns array so hold here to pluck out below
|
|
150
|
+
const currentPage = fullTree.filter(
|
|
151
|
+
(contentPage) => contentPage.id === this.content.id
|
|
152
|
+
)
|
|
153
|
+
this.selectedContent = currentPage[0] ? currentPage[0] : ''
|
|
154
|
+
}
|
|
155
|
+
return fullTree
|
|
156
|
+
},
|
|
157
|
+
taxonomyLevels() {
|
|
158
|
+
// Basic Bloom's taxonomy levels available to all question types
|
|
159
|
+
let basicBloomTaxonomy = [
|
|
160
|
+
{
|
|
161
|
+
value: 'None',
|
|
162
|
+
text: this.$t(
|
|
163
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
164
|
+
),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
value: 'Remember',
|
|
168
|
+
text: this.$t(
|
|
169
|
+
'windward.core.components.content.blocks.generate_questions.blooms.remember'
|
|
170
|
+
),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
value: 'Understand',
|
|
174
|
+
text: this.$t(
|
|
175
|
+
'windward.core.components.content.blocks.generate_questions.blooms.understand'
|
|
176
|
+
),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
value: 'Apply',
|
|
180
|
+
text: this.$t(
|
|
181
|
+
'windward.core.components.content.blocks.generate_questions.blooms.apply'
|
|
182
|
+
),
|
|
183
|
+
},
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
// Only add higher-level Bloom's taxonomy for supported question types
|
|
187
|
+
// Flashcards use only basic levels
|
|
188
|
+
if (
|
|
189
|
+
!this.isFlashcardType &&
|
|
190
|
+
(this.questionType === 'multi_choice_single_answer' ||
|
|
191
|
+
this.questionType === 'ordering' ||
|
|
192
|
+
this.questionType === 'multi_choice_multi_answer')
|
|
193
|
+
) {
|
|
194
|
+
const multiBlooms = [
|
|
195
|
+
{
|
|
196
|
+
value: 'Analyze',
|
|
197
|
+
text: this.$t(
|
|
198
|
+
'windward.core.components.content.blocks.generate_questions.blooms.analyze'
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
value: 'Evaluate',
|
|
203
|
+
text: this.$t(
|
|
204
|
+
'windward.core.components.content.blocks.generate_questions.blooms.evaluate'
|
|
205
|
+
),
|
|
206
|
+
},
|
|
207
|
+
]
|
|
208
|
+
basicBloomTaxonomy = basicBloomTaxonomy.concat(multiBlooms)
|
|
209
|
+
}
|
|
210
|
+
return basicBloomTaxonomy
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
methods: {
|
|
214
|
+
async generateAIQuestion() {
|
|
215
|
+
this.isLoading = true
|
|
216
|
+
try {
|
|
217
|
+
let bloomsRequest = ''
|
|
218
|
+
if (
|
|
219
|
+
this.selectedDifficulty.text !==
|
|
220
|
+
this.$t(
|
|
221
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
222
|
+
)
|
|
223
|
+
) {
|
|
224
|
+
bloomsRequest = `?blooms_level=${this.selectedDifficulty.value}`
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const course = new Course(this.course)
|
|
228
|
+
const content = new Content(
|
|
229
|
+
this.selectedContent || this.content
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
let response
|
|
233
|
+
if (this.questionType === 'flashcard') {
|
|
234
|
+
// FLASHCARD GENERATION
|
|
235
|
+
const activity = new Activity()
|
|
236
|
+
|
|
237
|
+
const endpoint = `suggest/flashcard${bloomsRequest}`
|
|
238
|
+
|
|
239
|
+
// Call the endpoint exactly like FlashCardSlidesManager does
|
|
240
|
+
response = await Activity.custom(
|
|
241
|
+
course,
|
|
242
|
+
content,
|
|
243
|
+
activity,
|
|
244
|
+
endpoint
|
|
245
|
+
).get()
|
|
246
|
+
|
|
247
|
+
let activityData = null
|
|
248
|
+
|
|
249
|
+
if (response && response.activity) {
|
|
250
|
+
activityData = response.activity
|
|
251
|
+
} else if (
|
|
252
|
+
response &&
|
|
253
|
+
response.length > 0 &&
|
|
254
|
+
response[0] &&
|
|
255
|
+
response[0].activity
|
|
256
|
+
) {
|
|
257
|
+
activityData = response[0].activity
|
|
258
|
+
} else if (Array.isArray(response) && response.length > 0) {
|
|
259
|
+
activityData = response[0]
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
activityData &&
|
|
264
|
+
activityData.metadata &&
|
|
265
|
+
activityData.metadata.config &&
|
|
266
|
+
activityData.metadata.config.cards &&
|
|
267
|
+
Array.isArray(activityData.metadata.config.cards)
|
|
268
|
+
) {
|
|
269
|
+
// We pass the activity data and the replace flag to the parent component
|
|
270
|
+
this.$emit(
|
|
271
|
+
'click:generate',
|
|
272
|
+
activityData,
|
|
273
|
+
this.replaceExisting
|
|
274
|
+
)
|
|
275
|
+
} else {
|
|
276
|
+
throw new Error(
|
|
277
|
+
'Invalid response from flashcard generation'
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// ASSESSMENT QUESTION GENERATION
|
|
282
|
+
const assessment = new Assessment({ id: this.block.id })
|
|
283
|
+
const question = new AssessmentQuestion()
|
|
284
|
+
|
|
285
|
+
response = await AssessmentQuestion.custom(
|
|
286
|
+
course,
|
|
287
|
+
content,
|
|
288
|
+
assessment,
|
|
289
|
+
question,
|
|
290
|
+
`suggest/${this.questionType}${bloomsRequest}`
|
|
291
|
+
).get()
|
|
292
|
+
|
|
293
|
+
if (response && response.length > 0) {
|
|
294
|
+
const generatedQuestion = response[0]
|
|
295
|
+
this.$emit('click:generate', generatedQuestion)
|
|
296
|
+
} else {
|
|
297
|
+
throw new Error(
|
|
298
|
+
'Invalid response from question generation'
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
const errorMessage =
|
|
304
|
+
error.response?.data?.error?.message ||
|
|
305
|
+
error.message ||
|
|
306
|
+
'assessment.error.technical'
|
|
307
|
+
const errorType = errorMessage.split('.').pop()
|
|
308
|
+
const basePath =
|
|
309
|
+
'windward.core.components.content.blocks.generate_questions.error'
|
|
310
|
+
|
|
311
|
+
let errorText =
|
|
312
|
+
this.$t(`${basePath}.${errorType}`) +
|
|
313
|
+
'\n\n' +
|
|
314
|
+
this.$t(`${basePath}.${errorType}_support`)
|
|
315
|
+
|
|
316
|
+
if (errorType === 'technical') {
|
|
317
|
+
const errorCode =
|
|
318
|
+
error.response?.data?.error?.details?.error_type ||
|
|
319
|
+
'UNKNOWN'
|
|
320
|
+
errorText = errorText.replace('[ERROR_CODE]', errorCode)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
this.$dialog.error(errorText, {
|
|
324
|
+
duration: 5000,
|
|
325
|
+
keepOnHover: true,
|
|
326
|
+
singleton: true,
|
|
327
|
+
type: 'error',
|
|
328
|
+
})
|
|
329
|
+
} finally {
|
|
330
|
+
this.isLoading = false
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
</script>
|
|
336
|
+
|
|
337
|
+
<style scoped>
|
|
338
|
+
.btn-selector {
|
|
339
|
+
width: 100%;
|
|
340
|
+
}
|
|
341
|
+
.container-generate-ai {
|
|
342
|
+
outline: 1px solid var(--v-secondary-base);
|
|
343
|
+
border-radius: 15px;
|
|
344
|
+
}
|
|
345
|
+
</style>
|
|
@@ -138,7 +138,7 @@ export default {
|
|
|
138
138
|
type: String,
|
|
139
139
|
required: false,
|
|
140
140
|
default:
|
|
141
|
-
'
|
|
141
|
+
'styles | bold italic underline strikethrough removeformat | alignleft aligncenter alignright | table tablerowprops tablecellprops |bullist numlist outdent indent |glossaryButton fibFormatButton mathButton a11yButton | undo redo',
|
|
142
142
|
},
|
|
143
143
|
rootBlock: { type: String, required: false, default: 'div' },
|
|
144
144
|
label: { type: String, required: false, default: '' },
|
|
@@ -212,7 +212,7 @@ export default {
|
|
|
212
212
|
},
|
|
213
213
|
format: {
|
|
214
214
|
title: 'Format',
|
|
215
|
-
items: ' bold italic underline strikethrough superscript subscript codeformat | formats align | language | removeformat',
|
|
215
|
+
items: ' bold italic underline strikethrough superscript subscript codeformat | formats align | language | removeformat | glossary',
|
|
216
216
|
},
|
|
217
217
|
},
|
|
218
218
|
autoresize_min_height: 100,
|
|
@@ -337,6 +337,9 @@ export default {
|
|
|
337
337
|
},
|
|
338
338
|
formats: {
|
|
339
339
|
glossary: {
|
|
340
|
+
title: this.$t(
|
|
341
|
+
'windward.core.components.utils.tiny_mce_wrapper.glossary'
|
|
342
|
+
),
|
|
340
343
|
inline: 'span',
|
|
341
344
|
attributes: {
|
|
342
345
|
'aria-label': this.$t(
|
|
@@ -378,67 +381,22 @@ export default {
|
|
|
378
381
|
],
|
|
379
382
|
},
|
|
380
383
|
style_formats: [
|
|
381
|
-
{
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
{ title: 'Heading 6', format: 'h6' },
|
|
389
|
-
],
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
title: 'Inline',
|
|
393
|
-
items: [
|
|
394
|
-
{ title: 'Bold', format: 'bold' },
|
|
395
|
-
{ title: 'Italic', format: 'italic' },
|
|
396
|
-
{ title: 'Underline', format: 'underline' },
|
|
397
|
-
{ title: 'Strikethrough', format: 'strikethrough' },
|
|
398
|
-
{ title: 'Superscript', format: 'superscript' },
|
|
399
|
-
{ title: 'Subscript', format: 'subscript' },
|
|
400
|
-
{ title: 'Code', format: 'code' },
|
|
401
|
-
],
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
title: 'Blocks',
|
|
405
|
-
items: [{ title: 'Paragraph', format: 'p' }],
|
|
406
|
-
},
|
|
407
|
-
{
|
|
408
|
-
title: 'Align',
|
|
409
|
-
items: [
|
|
410
|
-
{ title: 'Left', format: 'alignleft' },
|
|
411
|
-
{ title: 'Center', format: 'aligncenter' },
|
|
412
|
-
{ title: 'Right', format: 'alignright' },
|
|
413
|
-
{ title: 'Justify', format: 'alignjustify' },
|
|
414
|
-
],
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
title: 'LearningEdge',
|
|
418
|
-
items: [
|
|
419
|
-
{
|
|
420
|
-
title: this.$t(
|
|
421
|
-
'windward.core.components.utils.tiny_mce_wrapper.term'
|
|
422
|
-
),
|
|
423
|
-
format: 'glossary',
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
title: this.$t(
|
|
427
|
-
'windward.core.components.utils.tiny_mce_wrapper.fill_blank'
|
|
428
|
-
),
|
|
429
|
-
format: 'fib',
|
|
430
|
-
},
|
|
431
|
-
],
|
|
432
|
-
},
|
|
384
|
+
{ title: 'Normal Text', format: 'div' },
|
|
385
|
+
{ title: 'Paragraph', format: 'p' },
|
|
386
|
+
{ title: 'Heading 2', format: 'h2' },
|
|
387
|
+
{ title: 'Heading 3', format: 'h3' },
|
|
388
|
+
{ title: 'Heading 4', format: 'h4' },
|
|
389
|
+
{ title: 'Heading 5', format: 'h5' },
|
|
390
|
+
{ title: 'Heading 6', format: 'h6' },
|
|
433
391
|
],
|
|
434
392
|
placeholder: this.label
|
|
435
393
|
? this.label
|
|
436
394
|
: this.$t('components.content.settings.base.placeholder'),
|
|
437
|
-
//required as it will be displayed as inline style in tinymce renderer
|
|
395
|
+
// required as it will be displayed as inline style in tinymce renderer
|
|
438
396
|
skin: false,
|
|
439
397
|
content_css: this.$vuetify.theme.isDark ? 'dark' : 'default',
|
|
440
398
|
|
|
441
|
-
//we need to inject the glossary style directly
|
|
399
|
+
// we need to inject the glossary style directly
|
|
442
400
|
content_style:
|
|
443
401
|
ContentCss +
|
|
444
402
|
EditorCss +
|
|
@@ -477,7 +435,6 @@ export default {
|
|
|
477
435
|
this.text = this.value
|
|
478
436
|
}
|
|
479
437
|
},
|
|
480
|
-
|
|
481
438
|
methods: {
|
|
482
439
|
getEditor() {
|
|
483
440
|
if (this.$refs.editor && this.$refs.editor.editor) {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-container justify="center">
|
|
2
|
+
<v-container justify="center" class="pa-0">
|
|
3
3
|
<v-row justify="center" align="center">
|
|
4
4
|
<v-col cols="12">
|
|
5
5
|
<v-data-table
|
|
6
6
|
:key="tableKey"
|
|
7
7
|
:headers="headers"
|
|
8
8
|
:items="glossaryTerms"
|
|
9
|
+
:footer-props="{
|
|
10
|
+
'items-per-page-options': [5, -1],
|
|
11
|
+
}"
|
|
9
12
|
:search="search"
|
|
10
13
|
class="elevation-1"
|
|
11
14
|
>
|
|
@@ -35,9 +38,13 @@
|
|
|
35
38
|
>
|
|
36
39
|
<template #title>
|
|
37
40
|
{{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
selectedTerm.id
|
|
42
|
+
? $t(
|
|
43
|
+
'windward.core.pages.glossary.edit_term'
|
|
44
|
+
)
|
|
45
|
+
: $t(
|
|
46
|
+
'windward.core.pages.glossary.add_term'
|
|
47
|
+
)
|
|
41
48
|
}}
|
|
42
49
|
</template>
|
|
43
50
|
<template #trigger>
|
|
@@ -159,18 +166,16 @@
|
|
|
159
166
|
<script>
|
|
160
167
|
import { mapGetters, mapMutations, mapActions } from 'vuex'
|
|
161
168
|
import _ from 'lodash'
|
|
162
|
-
import
|
|
169
|
+
import CourseGlossaryTerm from '../../../models/CourseGlossaryTerm'
|
|
163
170
|
import CourseGlossaryForm from './CourseGlossaryForm'
|
|
164
171
|
import DialogBox from '~/components/Core/DialogBox.vue'
|
|
165
172
|
import Crypto from '~/helpers/Crypto'
|
|
166
173
|
import Course from '~/models/Course'
|
|
167
|
-
import CourseGlossaryTerm from '../../../models/CourseGlossaryTerm'
|
|
168
174
|
import SpeedDial from '~/components/Core/SpeedDial.vue'
|
|
169
|
-
import TextViewer from '~/components/Text/TextViewer.vue'
|
|
170
175
|
|
|
171
176
|
export default {
|
|
172
177
|
name: 'CourseGlossary',
|
|
173
|
-
components: { DialogBox, CourseGlossaryForm, SpeedDial
|
|
178
|
+
components: { DialogBox, CourseGlossaryForm, SpeedDial },
|
|
174
179
|
layout: 'course',
|
|
175
180
|
middleware: ['auth'],
|
|
176
181
|
props: {
|
|
@@ -142,7 +142,17 @@ export class WindwardPlugins {
|
|
|
142
142
|
'glossaryIcon',
|
|
143
143
|
this.$t('windward.core.components.utils.tiny_mce_wrapper.glossary'),
|
|
144
144
|
() => {
|
|
145
|
-
|
|
145
|
+
if (
|
|
146
|
+
this.editor.selection
|
|
147
|
+
.getSel()
|
|
148
|
+
.anchorNode.parentElement.classList.contains(
|
|
149
|
+
'glossary-word'
|
|
150
|
+
)
|
|
151
|
+
) {
|
|
152
|
+
this.editor.formatter.remove('glossary')
|
|
153
|
+
} else {
|
|
154
|
+
this.editor.formatter.apply('glossary')
|
|
155
|
+
}
|
|
146
156
|
}
|
|
147
157
|
)
|
|
148
158
|
this.addButtonToEditor(
|
|
@@ -210,13 +220,29 @@ export class WindwardPlugins {
|
|
|
210
220
|
itemKey: string,
|
|
211
221
|
itemText: string,
|
|
212
222
|
command: string,
|
|
213
|
-
icon: string
|
|
223
|
+
icon: string,
|
|
224
|
+
type: string = 'command'
|
|
214
225
|
): void {
|
|
215
226
|
this.editor.ui.registry.addMenuItem(itemKey, {
|
|
216
227
|
text: itemText,
|
|
217
228
|
icon,
|
|
218
229
|
onAction: () => {
|
|
219
|
-
|
|
230
|
+
switch (type) {
|
|
231
|
+
case 'format':
|
|
232
|
+
if (
|
|
233
|
+
this.editor.selection
|
|
234
|
+
.getNode()
|
|
235
|
+
.classList.contains('glossary-word')
|
|
236
|
+
) {
|
|
237
|
+
this.editor.formatter.remove(command)
|
|
238
|
+
} else {
|
|
239
|
+
this.editor.formatter.apply(command)
|
|
240
|
+
}
|
|
241
|
+
break
|
|
242
|
+
default:
|
|
243
|
+
this.editor.execCommand(command, true)
|
|
244
|
+
break
|
|
245
|
+
}
|
|
220
246
|
},
|
|
221
247
|
})
|
|
222
248
|
}
|
|
@@ -233,6 +259,13 @@ export class WindwardPlugins {
|
|
|
233
259
|
'fib-window',
|
|
234
260
|
'fibIcon'
|
|
235
261
|
)
|
|
262
|
+
this.addEditorMenuItem(
|
|
263
|
+
'glossary',
|
|
264
|
+
'Glossary',
|
|
265
|
+
'glossary',
|
|
266
|
+
'glossaryIcon',
|
|
267
|
+
'format'
|
|
268
|
+
)
|
|
236
269
|
}
|
|
237
270
|
|
|
238
271
|
/**
|
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
error: {
|
|
3
3
|
default: 'Could not generate question from provided content.',
|
|
4
|
-
default_support:
|
|
5
|
-
|
|
4
|
+
default_support:
|
|
5
|
+
'Please try again or contact support if the issue persists.',
|
|
6
|
+
|
|
6
7
|
insufficient_content: 'More content needed to generate questions.',
|
|
7
|
-
insufficient_content_support:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
insufficient_content_support:
|
|
9
|
+
'Please add more text, examples, or explanations to this section. We recommend at least 50 words of relevant content to generate appropriate questions.',
|
|
10
|
+
|
|
11
|
+
content_mismatch: "Content doesn't match question type.",
|
|
12
|
+
content_mismatch_support:
|
|
13
|
+
"The current content isn't suitable for this type of question. Consider adding more specific examples, numerical data, or comparable items depending on your desired question type.",
|
|
14
|
+
|
|
12
15
|
llm_unavailable: 'Question generation temporarily unavailable.',
|
|
13
|
-
llm_unavailable_support:
|
|
14
|
-
|
|
16
|
+
llm_unavailable_support:
|
|
17
|
+
"We're unable to connect to our AI service at the moment. Please try again in a few minutes or contact support if the issue persists.",
|
|
18
|
+
|
|
15
19
|
technical: 'Unable to process request.',
|
|
16
|
-
technical_support:
|
|
20
|
+
technical_support:
|
|
21
|
+
'Something went wrong on our end. Please try again or contact support if this continues. Reference code: [ERROR_CODE]',
|
|
17
22
|
},
|
|
18
23
|
button_label: 'Generate Question',
|
|
19
|
-
selected_pages: 'Selected Page'
|
|
24
|
+
selected_pages: 'Selected Page',
|
|
25
|
+
ai_assistance: 'AI Assistance',
|
|
26
|
+
blooms: {
|
|
27
|
+
blooms_taxonomy: "Bloom's Taxonomy Level",
|
|
28
|
+
none: 'None selected',
|
|
29
|
+
remember: 'Remember',
|
|
30
|
+
understand: 'Understand',
|
|
31
|
+
apply: 'Apply',
|
|
32
|
+
analyze: 'Analyze',
|
|
33
|
+
evaluate: 'Evaluate',
|
|
34
|
+
},
|
|
20
35
|
}
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
math: 'Math',
|
|
9
9
|
accordion: 'Accordion',
|
|
10
10
|
open_response: 'Open Response',
|
|
11
|
-
open_response_collate: 'Open Response
|
|
11
|
+
open_response_collate: 'Open Response Download',
|
|
12
12
|
image: 'Image',
|
|
13
13
|
user_upload: 'User Upload',
|
|
14
14
|
clickable_icons: 'Clickable Icons',
|
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
title: {
|
|
3
3
|
assessment: 'Assessment Settings',
|
|
4
4
|
open_response: 'Open Response Settings',
|
|
5
|
-
open_response_collate: 'Open Response
|
|
5
|
+
open_response_collate: 'Open Response Download Settings',
|
|
6
6
|
image: 'Image Settings',
|
|
7
7
|
user_upload: 'User Upload Settings',
|
|
8
8
|
file_download: 'File Download Settings',
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
|
|
13
13
|
content_mismatch: 'El contenido no coincide con el tipo de pregunta.',
|
|
14
14
|
content_mismatch_support:
|
|
15
|
-
'
|
|
15
|
+
'Por favor, añada más texto, ejemplos o explicaciones a esta sección. Recomendamos al menos 50 palabras de contenido relevante para generar preguntas apropiadas.',
|
|
16
16
|
|
|
17
17
|
llm_unavailable:
|
|
18
18
|
'La generación de preguntas no está disponible temporalmente.',
|
|
@@ -25,4 +25,14 @@ export default {
|
|
|
25
25
|
},
|
|
26
26
|
button_label: 'Generar pregunta',
|
|
27
27
|
selected_pages: 'Página seleccionada',
|
|
28
|
+
ai_assistance: 'Asistencia de IA',
|
|
29
|
+
blooms: {
|
|
30
|
+
blooms_taxonomy: 'Nivel de taxonomía de Bloom',
|
|
31
|
+
none: 'Ninguno seleccionado',
|
|
32
|
+
remember: 'Recordar',
|
|
33
|
+
understand: 'Entender',
|
|
34
|
+
apply: 'Aplicar',
|
|
35
|
+
analyze: 'Analizar',
|
|
36
|
+
evaluate: 'Evaluar',
|
|
37
|
+
},
|
|
28
38
|
}
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
math: 'Matemáticas',
|
|
9
9
|
accordion: 'Acordeón',
|
|
10
10
|
open_response: 'Respuesta abierta',
|
|
11
|
-
open_response_collate: '
|
|
11
|
+
open_response_collate: 'Módulo de descarga de respuestas',
|
|
12
12
|
image: 'Imagen',
|
|
13
13
|
user_upload: 'Carga de usuario',
|
|
14
14
|
clickable_icons: 'Iconos en los que se puede hacer clic',
|