@windward/core 0.24.0 → 0.25.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.
- package/CHANGELOG.md +77 -66
- package/components/Content/Blocks/OpenResponse.vue +11 -1
- package/components/Settings/ClickableIconsSettings.vue +7 -3
- package/components/Settings/OpenResponseSettings.vue +55 -6
- package/components/utils/TinyMCEWrapper.vue +313 -3
- package/helpers/tinymce/WindwardPlugins.ts +65 -1
- package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +7 -0
- package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +8 -0
- package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +8 -0
- package/package.json +1 -1
- package/plugin.js +0 -44
- package/test/mocks.js +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,87 +1,98 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Hotfix [0.25.1] - 2025-11-07
|
|
4
4
|
|
|
5
|
-
* Merged in
|
|
6
|
-
* Merged in feature/LE-
|
|
7
|
-
* Merged release/0.24.0 into feature/LE-2097-tabs-and-accordions-hide-backgro
|
|
8
|
-
* Merged in bugfix/LE-1841-all-blocks-save-or-cancel-change (pull request #440)
|
|
9
|
-
* Merged release/0.24.0 into bugfix/LE-1841-all-blocks-save-or-cancel-change
|
|
10
|
-
* Merged in feature/LE-2100-edit-in-text-area-update-text-fi (pull request #435)
|
|
5
|
+
* Merged in feature/LE-2108/revise-text-fix (pull request #453)
|
|
6
|
+
* Merged in feature/LE-2123/open-res-gen-fix (pull request #452)
|
|
11
7
|
|
|
12
8
|
|
|
13
|
-
## Release [0.
|
|
9
|
+
## Release [0.25.0] - 2025-10-29
|
|
14
10
|
|
|
15
|
-
* Merged in
|
|
16
|
-
* Merged in
|
|
17
|
-
*
|
|
18
|
-
* Merged in
|
|
19
|
-
* Merged in
|
|
20
|
-
* Merged in
|
|
21
|
-
* Merged in bugfix/LE-2052-clickable-icon-text-color-should (pull request #426)
|
|
22
|
-
* Merged in bugfix/LE-2088-open-response-block-remove-edito (pull request #430)
|
|
23
|
-
* Merged release/0.23.0 into bugfix/LE-2071-vimeo-videos-not-working
|
|
24
|
-
* Merged release/0.22.0 into bugfix/LE-2052-clickable-icon-text-color-should
|
|
11
|
+
* Merged in bugfix/LE-2067-scorm-provider (pull request #451)
|
|
12
|
+
* Merged in feature/LE-2108/revise-text (pull request #445)
|
|
13
|
+
* Merge remote-tracking branch 'origin/release/0.24.0' into release/0.25.0
|
|
14
|
+
* Merged in feature/LE-2123/open-res-gen (pull request #446)
|
|
15
|
+
* Merged in feature/LE-2127-increase-clickable-icon-item-tit (pull request #450)
|
|
16
|
+
* Merged in feature/LE-2157-remove-user-uploads-and-glossary (pull request #449)
|
|
25
17
|
|
|
26
18
|
|
|
27
|
-
## Release [0.
|
|
19
|
+
## Release [0.24.0] - 2025-10-06
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* Merged in bugfix/LE-2057-save-button-disappeared-again-on (pull request #419)
|
|
37
|
-
* Merged release/0.22.0 into bugfix/LE-1960-video-using-urls-as-a-source
|
|
38
|
-
* Merged in feature/LE-2036/word-jumble-gen (pull request #420)
|
|
39
|
-
* Merged in feature/LE-1997/scenario-gen (pull request #416)
|
|
40
|
-
* Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #415)
|
|
41
|
-
* Merged in release/0.21.0 (pull request #401)
|
|
42
|
-
* Merged release/0.21.0 into bugfix/LE-1960-video-using-urls-as-a-source
|
|
43
|
-
* Merged release/0.21.0 into bugfix/LE-1928-user-upload-allowed-file-types
|
|
21
|
+
- Merged in feature/LE-2123/open-res-gen (pull request #446)
|
|
22
|
+
- Merged in bugfix/LE-2134-email-block-show-hide-title (pull request #444)
|
|
23
|
+
- Merged in feature/LE-2097-tabs-and-accordions-hide-backgro (pull request #436)
|
|
24
|
+
- Merged release/0.24.0 into feature/LE-2097-tabs-and-accordions-hide-backgro
|
|
25
|
+
- Merged in bugfix/LE-1841-all-blocks-save-or-cancel-change (pull request #440)
|
|
26
|
+
- Merged release/0.24.0 into bugfix/LE-1841-all-blocks-save-or-cancel-change
|
|
27
|
+
- Merged in feature/LE-2100-edit-in-text-area-update-text-fi (pull request #435)
|
|
44
28
|
|
|
29
|
+
## Release [0.23.0] - 2025-09-18
|
|
45
30
|
|
|
46
|
-
|
|
31
|
+
- Merged in feature/LE-2099-track-engagement-on-videos-from- (pull request #439)
|
|
32
|
+
- Merged in bugfix/LE-2071-vimeo-videos-not-working (pull request #438)
|
|
33
|
+
- Merged in bugfix/LE-2071-vimeo-videos-not-working (pull request #437)
|
|
34
|
+
- Merged in bugfix/LE-2088-open-response-block-remove-edito (pull request #434)
|
|
35
|
+
- Merged in bugfix/MIND-6075-decouple-generateaiquestionbut (pull request #432)
|
|
36
|
+
- Merged in bugfix/LE-2071-vimeo-videos-not-working (pull request #433)
|
|
37
|
+
- Merged in bugfix/LE-2052-clickable-icon-text-color-should (pull request #426)
|
|
38
|
+
- Merged in bugfix/LE-2088-open-response-block-remove-edito (pull request #430)
|
|
39
|
+
- Merged release/0.23.0 into bugfix/LE-2071-vimeo-videos-not-working
|
|
40
|
+
- Merged release/0.22.0 into bugfix/LE-2052-clickable-icon-text-color-should
|
|
47
41
|
|
|
42
|
+
## Release [0.22.0] - 2025-08-28
|
|
48
43
|
|
|
49
|
-
|
|
44
|
+
- Merge branch 'master' into release/0.22.0
|
|
45
|
+
- Merged in bugfix/LE-2075-the-panel-of-the-text-block-isnt (pull request #427)
|
|
46
|
+
- Merged in bug-fix/LE-2060/llm-character-limit-validation (pull request #421)
|
|
47
|
+
- Merged in bugfix/LE-2031-open-response-download-collate-q (pull request #422)
|
|
48
|
+
- Merged in bugfix/LE-1960-video-using-urls-as-a-source (pull request #423)
|
|
49
|
+
- Merged in hotfix/0.21.1 (pull request #425)
|
|
50
|
+
- Merged release/0.22.0 into bugfix/LE-1960-video-using-urls-as-a-source
|
|
51
|
+
- Merged in bugfix/LE-2057-save-button-disappeared-again-on (pull request #419)
|
|
52
|
+
- Merged release/0.22.0 into bugfix/LE-1960-video-using-urls-as-a-source
|
|
53
|
+
- Merged in feature/LE-2036/word-jumble-gen (pull request #420)
|
|
54
|
+
- Merged in feature/LE-1997/scenario-gen (pull request #416)
|
|
55
|
+
- Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #415)
|
|
56
|
+
- Merged in release/0.21.0 (pull request #401)
|
|
57
|
+
- Merged release/0.21.0 into bugfix/LE-1960-video-using-urls-as-a-source
|
|
58
|
+
- Merged release/0.21.0 into bugfix/LE-1928-user-upload-allowed-file-types
|
|
59
|
+
|
|
60
|
+
## Hotfix [0.21.1] created - 2025-08-20
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
* Merged in feature/LE-2009-organizations-custom-color-palle (pull request #410)
|
|
53
|
-
* Merged in feature/LE-2011-open-response-download-field-to- (pull request #411)
|
|
54
|
-
* Merged in feature/LE-1912/sorting-game-gen-2 (pull request #413)
|
|
55
|
-
* Merged in feature/LE-2029-open-response-block-design (pull request #412)
|
|
56
|
-
* Merged in feature/LE-1912/sorting-game-gen (pull request #409)
|
|
57
|
-
* Merged in feature/LE-2011-open-response-download-field-to- (pull request #408)
|
|
58
|
-
* Merged in feature/LE-1924-clickable-icons-ux (pull request #407)
|
|
59
|
-
* Merged in feature/LE-1913/matching-block (pull request #405)
|
|
60
|
-
* Merged in feature/LE-1924-clickable-icons-ux (pull request #404)
|
|
61
|
-
* Merged in feature/LE-2011-open-response-download-field-to- (pull request #406)
|
|
62
|
-
* Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #398)
|
|
63
|
-
* Merged release/0.21.0 into feature/LE-2011-open-response-download-field-to-
|
|
64
|
-
* Merge branch 'release/0.21.0' into feature/LE-1913/matching-block
|
|
65
|
-
* Merged in bugfix/LE-1990-video-black-line-on-left-and-rig (pull request #403)
|
|
66
|
-
* Merged in feature/LE-1900-fill-in-the-blank-formatting-sho (pull request #402)
|
|
67
|
-
* Merged release/0.21.0 into feature/LE-1924-clickable-icons-ux
|
|
68
|
-
* Merge branch 'release/0.20.0' into feature/LE-1913/matching-block
|
|
62
|
+
## Release [0.21.0] - 2025-08-01
|
|
69
63
|
|
|
64
|
+
- Merged in feature/LE-2045/lableing-fixes (pull request #414)
|
|
65
|
+
- Merged in feature/LE-2009-organizations-custom-color-palle (pull request #410)
|
|
66
|
+
- Merged in feature/LE-2011-open-response-download-field-to- (pull request #411)
|
|
67
|
+
- Merged in feature/LE-1912/sorting-game-gen-2 (pull request #413)
|
|
68
|
+
- Merged in feature/LE-2029-open-response-block-design (pull request #412)
|
|
69
|
+
- Merged in feature/LE-1912/sorting-game-gen (pull request #409)
|
|
70
|
+
- Merged in feature/LE-2011-open-response-download-field-to- (pull request #408)
|
|
71
|
+
- Merged in feature/LE-1924-clickable-icons-ux (pull request #407)
|
|
72
|
+
- Merged in feature/LE-1913/matching-block (pull request #405)
|
|
73
|
+
- Merged in feature/LE-1924-clickable-icons-ux (pull request #404)
|
|
74
|
+
- Merged in feature/LE-2011-open-response-download-field-to- (pull request #406)
|
|
75
|
+
- Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #398)
|
|
76
|
+
- Merged release/0.21.0 into feature/LE-2011-open-response-download-field-to-
|
|
77
|
+
- Merge branch 'release/0.21.0' into feature/LE-1913/matching-block
|
|
78
|
+
- Merged in bugfix/LE-1990-video-black-line-on-left-and-rig (pull request #403)
|
|
79
|
+
- Merged in feature/LE-1900-fill-in-the-blank-formatting-sho (pull request #402)
|
|
80
|
+
- Merged release/0.21.0 into feature/LE-1924-clickable-icons-ux
|
|
81
|
+
- Merge branch 'release/0.20.0' into feature/LE-1913/matching-block
|
|
70
82
|
|
|
71
83
|
## Release [0.20.0] - 2025-07-01
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
- Merge remote-tracking branch 'origin/release/0.20.0' into release/0.20.0
|
|
86
|
+
- Merge remote-tracking branch 'origin/release/0.20.0' into release/0.20.0
|
|
87
|
+
- Merged in feature/LE-1948/empty-bucket-localization-fix (pull request #397)
|
|
88
|
+
- Merged in LE-1911-email-block-to-cc-and-subject-te (pull request #395)
|
|
89
|
+
- Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #391)
|
|
90
|
+
- Merged in bugfix/LE-1941-divider-dashed-line-renders-soli (pull request #396)
|
|
91
|
+
- Merged in feature/LE-1948/empty-bucket (pull request #393)
|
|
92
|
+
- Merged in feature/LE-1906-ai-assistant-button-text (pull request #394)
|
|
93
|
+
- Merged in bugfix/LE-1739-email-block-to-cc-and-subject-te (pull request #392)
|
|
94
|
+
- Merged in bugfix/LE-1917-student-experience-cleanup (pull request #386)
|
|
95
|
+
- Merged release/0.19.0 into bugfix/LE-1917-student-experience-cleanup
|
|
85
96
|
|
|
86
97
|
### Release [0.19.0] created - 2025-05-30
|
|
87
98
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
<v-container
|
|
4
4
|
v-if="
|
|
5
5
|
block.metadata.config.title ||
|
|
6
|
-
block.metadata.config.instructions
|
|
6
|
+
block.metadata.config.instructions ||
|
|
7
|
+
block.metadata.config.starting_text
|
|
7
8
|
"
|
|
8
9
|
class="pa-0"
|
|
9
10
|
>
|
|
@@ -24,6 +25,14 @@
|
|
|
24
25
|
>
|
|
25
26
|
{{ block.metadata.config.instructions }}
|
|
26
27
|
</p>
|
|
28
|
+
|
|
29
|
+
<p
|
|
30
|
+
v-if="block.metadata.config.starting_text"
|
|
31
|
+
tabindex="0"
|
|
32
|
+
class="pt-3"
|
|
33
|
+
>
|
|
34
|
+
{{ block.metadata.config.starting_text }}
|
|
35
|
+
</p>
|
|
27
36
|
</v-container>
|
|
28
37
|
<div v-if="stateLoaded">
|
|
29
38
|
<div v-if="block.body && !submitted">
|
|
@@ -173,6 +182,7 @@ export default {
|
|
|
173
182
|
}
|
|
174
183
|
if (_.isEmpty(this.block.metadata.config.starting_text)) {
|
|
175
184
|
this.block.metadata.config.starting_text = ''
|
|
185
|
+
|
|
176
186
|
}
|
|
177
187
|
},
|
|
178
188
|
mounted() {},
|
|
@@ -163,13 +163,17 @@
|
|
|
163
163
|
hide-modal
|
|
164
164
|
></ImageAssetSettings>
|
|
165
165
|
<v-text-field
|
|
166
|
+
:id="'item-' + index + '-title'"
|
|
166
167
|
v-model="
|
|
167
168
|
block.metadata.config.items[index].title
|
|
168
169
|
"
|
|
169
|
-
:id="'item-' + index + '-title'"
|
|
170
170
|
outlined
|
|
171
|
-
:rules="
|
|
172
|
-
|
|
171
|
+
:rules="
|
|
172
|
+
$Validation.getRule('clickableIconInput')
|
|
173
|
+
"
|
|
174
|
+
:counter="
|
|
175
|
+
$Validation.getLimit('clickableIconInput')
|
|
176
|
+
"
|
|
173
177
|
:label="
|
|
174
178
|
$t(
|
|
175
179
|
'windward.core.components.settings.clickable_icon.item_title'
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-container>
|
|
2
|
+
<v-container class="pb-6">
|
|
3
3
|
<v-row>
|
|
4
4
|
<BaseContentBlockSettings
|
|
5
5
|
v-model="block.metadata.config"
|
|
6
6
|
:disabled="render"
|
|
7
7
|
></BaseContentBlockSettings>
|
|
8
8
|
</v-row>
|
|
9
|
-
<p>
|
|
10
|
-
{{
|
|
9
|
+
<p class="pt-4 mb-2">
|
|
10
|
+
{{
|
|
11
|
+
$t('windward.core.components.settings.open_response.question')
|
|
12
|
+
}}
|
|
11
13
|
</p>
|
|
12
14
|
<TextEditor
|
|
13
15
|
id="block-settings-body"
|
|
@@ -41,18 +43,36 @@
|
|
|
41
43
|
:height="200"
|
|
42
44
|
:disabled="render"
|
|
43
45
|
></TextEditor>
|
|
46
|
+
<v-row class="pt-6">
|
|
47
|
+
<v-col cols="12">
|
|
48
|
+
<PluginRef
|
|
49
|
+
target="contentBlockSettingTool"
|
|
50
|
+
:attrs="{
|
|
51
|
+
value: block,
|
|
52
|
+
course,
|
|
53
|
+
content: currentContent,
|
|
54
|
+
}"
|
|
55
|
+
:on="{
|
|
56
|
+
input: onApplyGeneratedBlock,
|
|
57
|
+
append: onApplyGeneratedBlock,
|
|
58
|
+
}"
|
|
59
|
+
></PluginRef>
|
|
60
|
+
</v-col>
|
|
61
|
+
</v-row>
|
|
44
62
|
</v-container>
|
|
45
63
|
</template>
|
|
46
64
|
|
|
47
65
|
<script>
|
|
48
66
|
import _ from 'lodash'
|
|
67
|
+
import { mapGetters } from 'vuex'
|
|
49
68
|
import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
|
|
50
69
|
import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
|
|
70
|
+
import PluginRef from '~/components/Core/PluginRef.vue'
|
|
51
71
|
import TextEditor from '~/components/Text/TextEditor'
|
|
52
72
|
|
|
53
73
|
export default {
|
|
54
|
-
name: '
|
|
55
|
-
components: { TextEditor, BaseContentBlockSettings },
|
|
74
|
+
name: 'OpenResponseSettings',
|
|
75
|
+
components: { TextEditor, BaseContentBlockSettings, PluginRef },
|
|
56
76
|
extends: BaseContentSettings,
|
|
57
77
|
props: {
|
|
58
78
|
settings: { type: Object, required: false, default: null },
|
|
@@ -61,6 +81,12 @@ export default {
|
|
|
61
81
|
data() {
|
|
62
82
|
return {}
|
|
63
83
|
},
|
|
84
|
+
computed: {
|
|
85
|
+
...mapGetters({
|
|
86
|
+
course: 'course/get',
|
|
87
|
+
currentContent: 'content/get',
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
64
90
|
beforeMount() {
|
|
65
91
|
if (_.isEmpty(this.block)) {
|
|
66
92
|
this.block = {}
|
|
@@ -91,6 +117,29 @@ export default {
|
|
|
91
117
|
}
|
|
92
118
|
},
|
|
93
119
|
mounted() {},
|
|
94
|
-
methods: {
|
|
120
|
+
methods: {
|
|
121
|
+
onApplyGeneratedBlock(payload = {}) {
|
|
122
|
+
if (_.isEmpty(payload)) {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const generatedBlock = _.cloneDeep(payload)
|
|
127
|
+
const config = _.get(generatedBlock, 'metadata.config', {})
|
|
128
|
+
|
|
129
|
+
this.block.body = _.get(generatedBlock, 'body', '') ?? ''
|
|
130
|
+
this.block.metadata.config.title =
|
|
131
|
+
_.get(config, 'title', '') ?? ''
|
|
132
|
+
this.block.metadata.config.instructions =
|
|
133
|
+
_.get(config, 'instructions', '') ?? ''
|
|
134
|
+
this.block.metadata.config.sample_response =
|
|
135
|
+
_.get(config, 'sample_response', '') ?? ''
|
|
136
|
+
this.block.metadata.config.starting_text =
|
|
137
|
+
_.get(config, 'starting_text', '') ?? ''
|
|
138
|
+
|
|
139
|
+
if (_.has(config, 'display_title')) {
|
|
140
|
+
this.block.metadata.config.display_title = config.display_title
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
},
|
|
95
144
|
}
|
|
96
145
|
</script>
|
|
@@ -66,6 +66,7 @@ import _ from 'lodash'
|
|
|
66
66
|
import 'tinymce'
|
|
67
67
|
import Editor from '@tinymce/tinymce-vue'
|
|
68
68
|
import { getTinymce } from '@tinymce/tinymce-vue/lib/cjs/main/ts/TinyMCE'
|
|
69
|
+
import { mapGetters } from 'vuex'
|
|
69
70
|
/* Required TinyMCE components */
|
|
70
71
|
import 'tinymce/icons/default/icons.min.js'
|
|
71
72
|
import 'tinymce/themes/silver/theme.min.js'
|
|
@@ -119,6 +120,8 @@ import Crypto from '~/helpers/Crypto'
|
|
|
119
120
|
import GlossaryVerification from '../Glossary/GlossaryVerification.vue'
|
|
120
121
|
import MathHelper from '../../helpers/MathHelper'
|
|
121
122
|
import { WindwardPlugins } from '../../helpers/tinymce/WindwardPlugins'
|
|
123
|
+
import Course from '~/models/Course'
|
|
124
|
+
import Organization from '~/models/Organization'
|
|
122
125
|
|
|
123
126
|
import ContentCss from '!raw-loader!sass-loader!./assets/tinymce/content/global.scss'
|
|
124
127
|
import EditorCss from '!raw-loader!sass-loader!./assets/tinymce/ui/global.scss'
|
|
@@ -143,7 +146,7 @@ export default {
|
|
|
143
146
|
type: String,
|
|
144
147
|
required: false,
|
|
145
148
|
default:
|
|
146
|
-
'styles | bold italic underline strikethrough removeformat | alignleft aligncenter alignright | table tablerowprops tablecellprops |bullist numlist outdent indent |glossaryButton fibFormatButton mathButton a11yButton | undo redo',
|
|
149
|
+
'styles | bold italic underline strikethrough removeformat | alignleft aligncenter alignright | table tablerowprops tablecellprops |bullist numlist outdent indent |glossaryButton fibFormatButton mathButton a11yButton reviseText | undo redo',
|
|
147
150
|
},
|
|
148
151
|
rootBlock: { type: String, required: false, default: 'div' },
|
|
149
152
|
label: { type: String, required: false, default: '' },
|
|
@@ -160,10 +163,17 @@ export default {
|
|
|
160
163
|
seed: Crypto.id(),
|
|
161
164
|
synthesizer: null,
|
|
162
165
|
paused: false,
|
|
166
|
+
isRevising: false,
|
|
167
|
+
rephraseToneIndex: 0,
|
|
168
|
+
toneSequence: ['neutral', 'conversational', 'formal', 'succinct', 'encouraging'],
|
|
163
169
|
}
|
|
164
170
|
},
|
|
165
171
|
|
|
166
172
|
computed: {
|
|
173
|
+
...mapGetters({
|
|
174
|
+
organization: 'organization/get',
|
|
175
|
+
course: 'course/get',
|
|
176
|
+
}),
|
|
167
177
|
hasActions() {
|
|
168
178
|
if (this.allowRead && !this.render) {
|
|
169
179
|
return true
|
|
@@ -346,12 +356,14 @@ export default {
|
|
|
346
356
|
value: 'windward-table-subject-report',
|
|
347
357
|
},
|
|
348
358
|
],
|
|
349
|
-
setup(
|
|
359
|
+
setup: () => {
|
|
350
360
|
// Here we can add plugin
|
|
351
361
|
getTinymce().PluginManager.add(
|
|
352
362
|
'WindwardToolKit',
|
|
353
363
|
(editor) => {
|
|
354
|
-
new WindwardPlugins(editor
|
|
364
|
+
new WindwardPlugins(editor, {
|
|
365
|
+
onRevise: this.handleRevision,
|
|
366
|
+
})
|
|
355
367
|
}
|
|
356
368
|
)
|
|
357
369
|
},
|
|
@@ -519,6 +531,304 @@ export default {
|
|
|
519
531
|
return true
|
|
520
532
|
}
|
|
521
533
|
},
|
|
534
|
+
getRevisionContext() {
|
|
535
|
+
return {
|
|
536
|
+
organizationId: this.organization?.id ?? null,
|
|
537
|
+
courseId: this.course?.id ?? null,
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
selectionContainsProtected(node) {
|
|
541
|
+
if (!node) {
|
|
542
|
+
return false
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (typeof Node === 'undefined') {
|
|
546
|
+
return false
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const editor = this.getEditor()
|
|
550
|
+
const body = editor ? editor.getBody() : null
|
|
551
|
+
const protectedClasses = [
|
|
552
|
+
'windward-math-content',
|
|
553
|
+
'windward-fill-blank',
|
|
554
|
+
'glossary-word',
|
|
555
|
+
]
|
|
556
|
+
|
|
557
|
+
let current = node
|
|
558
|
+
|
|
559
|
+
while (current && current !== body) {
|
|
560
|
+
if (current.nodeType === Node.ELEMENT_NODE) {
|
|
561
|
+
const classList = current.classList || []
|
|
562
|
+
if (
|
|
563
|
+
protectedClasses.some((className) =>
|
|
564
|
+
classList.contains(className)
|
|
565
|
+
)
|
|
566
|
+
) {
|
|
567
|
+
return true
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
current = current.parentNode
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return false
|
|
574
|
+
},
|
|
575
|
+
nextTone(operation) {
|
|
576
|
+
if (operation !== 'rephrase') {
|
|
577
|
+
this.rephraseToneIndex = 0
|
|
578
|
+
|
|
579
|
+
return null
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const tone = this.toneSequence[
|
|
583
|
+
this.rephraseToneIndex % this.toneSequence.length
|
|
584
|
+
]
|
|
585
|
+
this.rephraseToneIndex =
|
|
586
|
+
(this.rephraseToneIndex + 1) % this.toneSequence.length
|
|
587
|
+
|
|
588
|
+
return tone
|
|
589
|
+
},
|
|
590
|
+
async handleRevision(operation) {
|
|
591
|
+
const editor = this.getEditor()
|
|
592
|
+
if (!editor || this.isRevising) {
|
|
593
|
+
return
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const selection = editor.selection
|
|
597
|
+
const selectionHtml = selection
|
|
598
|
+
? selection.getContent({ format: 'html' })
|
|
599
|
+
: ''
|
|
600
|
+
const useSelection =
|
|
601
|
+
selection &&
|
|
602
|
+
!selection.isCollapsed() &&
|
|
603
|
+
selectionHtml.trim().length > 0
|
|
604
|
+
|
|
605
|
+
const targetHtml = useSelection
|
|
606
|
+
? selectionHtml
|
|
607
|
+
: editor.getContent({ format: 'html' })
|
|
608
|
+
|
|
609
|
+
if (!targetHtml || targetHtml.trim().length === 0) {
|
|
610
|
+
return
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const findBlockAncestor = (node) => {
|
|
614
|
+
try {
|
|
615
|
+
if (!node) return null
|
|
616
|
+
const body = editor ? editor.getBody() : null
|
|
617
|
+
let current = node
|
|
618
|
+
const isBlock = (n) => {
|
|
619
|
+
if (!n || n.nodeType !== Node.ELEMENT_NODE) return false
|
|
620
|
+
const name = n.nodeName || ''
|
|
621
|
+
return /^(P|DIV|LI|UL|OL|H1|H2|H3|H4|H5|H6)$/.test(name)
|
|
622
|
+
}
|
|
623
|
+
while (current && current !== body) {
|
|
624
|
+
if (isBlock(current)) return current
|
|
625
|
+
current = current.parentNode
|
|
626
|
+
}
|
|
627
|
+
return null
|
|
628
|
+
} catch (_e) {
|
|
629
|
+
return null
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (useSelection) {
|
|
634
|
+
const range = selection.getRng()
|
|
635
|
+
if (
|
|
636
|
+
this.selectionContainsProtected(range.startContainer) ||
|
|
637
|
+
this.selectionContainsProtected(range.endContainer)
|
|
638
|
+
) {
|
|
639
|
+
if (this.$toast) {
|
|
640
|
+
this.$toast.error(
|
|
641
|
+
this.$t(
|
|
642
|
+
'windward.core.components.utils.tiny_mce_wrapper.revision_protected_error'
|
|
643
|
+
)
|
|
644
|
+
)
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const { organizationId, courseId } = this.getRevisionContext()
|
|
652
|
+
|
|
653
|
+
if (!organizationId || !courseId) {
|
|
654
|
+
if (this.$toast) {
|
|
655
|
+
this.$toast.error(
|
|
656
|
+
this.$t(
|
|
657
|
+
'windward.core.components.utils.tiny_mce_wrapper.revision_error'
|
|
658
|
+
)
|
|
659
|
+
)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
return
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const tone = this.nextTone(operation)
|
|
666
|
+
const payload = {
|
|
667
|
+
operation,
|
|
668
|
+
html: targetHtml,
|
|
669
|
+
language: this.$i18n.locale,
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (tone) {
|
|
673
|
+
payload.tone = tone
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const revisionRequest = new Course()
|
|
677
|
+
revisionRequest.custom(
|
|
678
|
+
new Organization({ id: organizationId }),
|
|
679
|
+
new Course({ id: courseId }),
|
|
680
|
+
'llm-revise'
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
const resourcePath = revisionRequest._customResource
|
|
684
|
+
|
|
685
|
+
if (!resourcePath) {
|
|
686
|
+
if (this.$toast) {
|
|
687
|
+
this.$toast.error(
|
|
688
|
+
this.$t(
|
|
689
|
+
'windward.core.components.utils.tiny_mce_wrapper.revision_error'
|
|
690
|
+
)
|
|
691
|
+
)
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
this.isRevising = false
|
|
695
|
+
editor.setProgressState(false)
|
|
696
|
+
|
|
697
|
+
return
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
this.isRevising = true
|
|
701
|
+
editor.setProgressState(true)
|
|
702
|
+
let bookmark = null
|
|
703
|
+
if (!useSelection && selection) {
|
|
704
|
+
bookmark = selection.getBookmark(2, true)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
try {
|
|
708
|
+
const requestConfig = revisionRequest._reqConfig(
|
|
709
|
+
{
|
|
710
|
+
method: 'POST',
|
|
711
|
+
url: `${revisionRequest.baseURL()}/${resourcePath}`,
|
|
712
|
+
data: payload,
|
|
713
|
+
},
|
|
714
|
+
{ forceMethod: true }
|
|
715
|
+
)
|
|
716
|
+
|
|
717
|
+
const response = await revisionRequest.request(requestConfig)
|
|
718
|
+
const responseData = response?.data || response
|
|
719
|
+
|
|
720
|
+
if (!responseData || !responseData.html) {
|
|
721
|
+
throw new Error('missing_html')
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
editor.undoManager.transact(() => {
|
|
725
|
+
if (useSelection) {
|
|
726
|
+
try {
|
|
727
|
+
const rng = selection.getRng()
|
|
728
|
+
const startBlock = findBlockAncestor(
|
|
729
|
+
rng ? rng.startContainer : null
|
|
730
|
+
)
|
|
731
|
+
const endBlock = findBlockAncestor(
|
|
732
|
+
rng ? rng.endContainer : null
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
// If selection spans multiple block elements, expand to full blocks
|
|
736
|
+
if (
|
|
737
|
+
startBlock &&
|
|
738
|
+
endBlock &&
|
|
739
|
+
startBlock !== endBlock
|
|
740
|
+
) {
|
|
741
|
+
const expanded = editor.dom.createRng()
|
|
742
|
+
expanded.setStartBefore(startBlock)
|
|
743
|
+
expanded.setEndAfter(endBlock)
|
|
744
|
+
editor.selection.setRng(expanded)
|
|
745
|
+
}
|
|
746
|
+
} catch (_e) {
|
|
747
|
+
// If expansion fails, fall back to current selection
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Wrap response with temporary markers so we can reselect inserted content
|
|
751
|
+
const startId = `ww-revise-start-${this.seed}-${Date.now()}-${Math.random()
|
|
752
|
+
.toString(36)
|
|
753
|
+
.slice(2)}`
|
|
754
|
+
const endId = `ww-revise-end-${this.seed}-${Date.now()}-${Math.random()
|
|
755
|
+
.toString(36)
|
|
756
|
+
.slice(2)}`
|
|
757
|
+
const wrappedHtml =
|
|
758
|
+
`<span id="${startId}" data-ww-revise="s"></span>` +
|
|
759
|
+
responseData.html +
|
|
760
|
+
`<span id="${endId}" data-ww-revise="e"></span>`
|
|
761
|
+
|
|
762
|
+
editor.selection.setContent(wrappedHtml)
|
|
763
|
+
|
|
764
|
+
// Try to reselect the inserted content and remove markers
|
|
765
|
+
try {
|
|
766
|
+
const doc = editor.getDoc()
|
|
767
|
+
const startEl = doc.getElementById(startId)
|
|
768
|
+
const endEl = doc.getElementById(endId)
|
|
769
|
+
if (startEl && endEl) {
|
|
770
|
+
const selectRange = editor.dom.createRng()
|
|
771
|
+
// Select everything between markers
|
|
772
|
+
if (selectRange.setStartAfter && selectRange.setEndBefore) {
|
|
773
|
+
selectRange.setStartAfter(startEl)
|
|
774
|
+
selectRange.setEndBefore(endEl)
|
|
775
|
+
} else {
|
|
776
|
+
// Fallback to parent/offset if needed
|
|
777
|
+
const startParent = startEl.parentNode
|
|
778
|
+
const endParent = endEl.parentNode
|
|
779
|
+
const childIndex = (node) => {
|
|
780
|
+
let i = 0
|
|
781
|
+
let cur = node
|
|
782
|
+
while (cur && cur.previousSibling) {
|
|
783
|
+
i++
|
|
784
|
+
cur = cur.previousSibling
|
|
785
|
+
}
|
|
786
|
+
return i
|
|
787
|
+
}
|
|
788
|
+
const startIndex = childIndex(startEl) + 1
|
|
789
|
+
const endIndex = childIndex(endEl)
|
|
790
|
+
selectRange.setStart(startParent, startIndex)
|
|
791
|
+
selectRange.setEnd(endParent, endIndex)
|
|
792
|
+
}
|
|
793
|
+
editor.selection.setRng(selectRange)
|
|
794
|
+
|
|
795
|
+
// Remove markers after selection is set
|
|
796
|
+
if (startEl.parentNode) startEl.parentNode.removeChild(startEl)
|
|
797
|
+
if (endEl.parentNode) endEl.parentNode.removeChild(endEl)
|
|
798
|
+
|
|
799
|
+
}
|
|
800
|
+
} catch (_e) {
|
|
801
|
+
// Ignore selection restoration errors
|
|
802
|
+
}
|
|
803
|
+
} else {
|
|
804
|
+
editor.setContent(responseData.html)
|
|
805
|
+
}
|
|
806
|
+
})
|
|
807
|
+
|
|
808
|
+
editor.fire('change')
|
|
809
|
+
|
|
810
|
+
if (!useSelection && bookmark) {
|
|
811
|
+
try {
|
|
812
|
+
editor.selection.moveToBookmark(bookmark)
|
|
813
|
+
} catch (_error) {
|
|
814
|
+
editor.selection.select(editor.getBody(), true)
|
|
815
|
+
editor.selection.collapse(false)
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
} catch (error) {
|
|
819
|
+
console.error('TinyMCE revision failed', error)
|
|
820
|
+
if (this.$toast) {
|
|
821
|
+
this.$toast.error(
|
|
822
|
+
this.$t(
|
|
823
|
+
'windward.core.components.utils.tiny_mce_wrapper.revision_error'
|
|
824
|
+
)
|
|
825
|
+
)
|
|
826
|
+
}
|
|
827
|
+
} finally {
|
|
828
|
+
this.isRevising = false
|
|
829
|
+
editor.setProgressState(false)
|
|
830
|
+
}
|
|
831
|
+
},
|
|
522
832
|
},
|
|
523
833
|
}
|
|
524
834
|
</script>
|
|
@@ -5,17 +5,29 @@ import local from '../../i18n/index'
|
|
|
5
5
|
/**
|
|
6
6
|
* Class representing the WindwardPlugins.
|
|
7
7
|
*/
|
|
8
|
+
type RevisionOptions = {
|
|
9
|
+
onRevise?: (operation: string) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type RevisionMenuItem = {
|
|
13
|
+
type: 'menuitem'
|
|
14
|
+
text: string
|
|
15
|
+
onAction: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
export class WindwardPlugins {
|
|
9
19
|
editor: any
|
|
10
20
|
formula: any
|
|
11
21
|
fillInBlank: any
|
|
12
22
|
private window: any
|
|
23
|
+
private options: RevisionOptions
|
|
13
24
|
|
|
14
|
-
constructor(editor: any) {
|
|
25
|
+
constructor(editor: any, options: RevisionOptions = {}) {
|
|
15
26
|
this.editor = editor
|
|
16
27
|
this.formula = undefined
|
|
17
28
|
this.fillInBlank = undefined
|
|
18
29
|
this.window = window
|
|
30
|
+
this.options = options
|
|
19
31
|
this.register()
|
|
20
32
|
}
|
|
21
33
|
|
|
@@ -70,6 +82,10 @@ export class WindwardPlugins {
|
|
|
70
82
|
'glossaryIcon',
|
|
71
83
|
'<svg viewBox="0 0 24 24" width="20px" height="20px" ><path d="M3,15H1V3A2,2 0 0,1 3,1H19V3H3V15M12,23A1,1 0 0,1 11,22V19H7A2,2 0 0,1 5,17V7A2,2 0 0,1 7,5H21A2,2 0 0,1 23,7V17A2,2 0 0,1 21,19H16.9L13.2,22.71C13,22.89 12.76,23 12.5,23H12M9,9V11H19V9H9M9,13V15H17V13H9Z"></path></svg>'
|
|
72
84
|
)
|
|
85
|
+
this.registerIcon(
|
|
86
|
+
'reviseIcon',
|
|
87
|
+
'<svg viewBox="0 0 24 24" width="20" height="20"><path d="M20.71,4.63L19.37,3.29C19,2.9 18.35,2.9 17.96,3.29L11,10.25L10.75,12.75L13.25,12.5L20.21,5.54C20.61,5.15 20.61,4.5 20.21,4.11M17,8L7,18L2,20L4,15L14,5L17,8Z"></path></svg>'
|
|
88
|
+
)
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
/**
|
|
@@ -188,6 +204,53 @@ export class WindwardPlugins {
|
|
|
188
204
|
)
|
|
189
205
|
}
|
|
190
206
|
|
|
207
|
+
private registerRevisionControls() {
|
|
208
|
+
const reviseLabel = this.$t(
|
|
209
|
+
'windward.core.components.utils.tiny_mce_wrapper.revise_text'
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
const items = [
|
|
213
|
+
{
|
|
214
|
+
text: this.$t(
|
|
215
|
+
'windward.core.components.utils.tiny_mce_wrapper.shorten'
|
|
216
|
+
),
|
|
217
|
+
value: 'shorten',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
text: this.$t(
|
|
221
|
+
'windward.core.components.utils.tiny_mce_wrapper.rephrase'
|
|
222
|
+
),
|
|
223
|
+
value: 'rephrase',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
text: this.$t(
|
|
227
|
+
'windward.core.components.utils.tiny_mce_wrapper.proofread'
|
|
228
|
+
),
|
|
229
|
+
value: 'proofread',
|
|
230
|
+
},
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
this.editor.ui.registry.addMenuButton('reviseText', {
|
|
234
|
+
icon: 'reviseIcon',
|
|
235
|
+
tooltip: reviseLabel,
|
|
236
|
+
fetch: (callback: (menuItems: RevisionMenuItem[]) => void) => {
|
|
237
|
+
callback(
|
|
238
|
+
items.map((item) => ({
|
|
239
|
+
type: 'menuitem',
|
|
240
|
+
text: item.text,
|
|
241
|
+
onAction: () => this.handleRevision(item.value),
|
|
242
|
+
}))
|
|
243
|
+
)
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private handleRevision(operation: string) {
|
|
249
|
+
if (this.options.onRevise) {
|
|
250
|
+
this.options.onRevise(operation)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
191
254
|
/**
|
|
192
255
|
* Add a button to the editor's UI registry
|
|
193
256
|
* @param {string} name Name of the button
|
|
@@ -470,6 +533,7 @@ export class WindwardPlugins {
|
|
|
470
533
|
private register() {
|
|
471
534
|
this.addIcons()
|
|
472
535
|
this.addButtons()
|
|
536
|
+
this.registerRevisionControls()
|
|
473
537
|
this.addMenuItems()
|
|
474
538
|
this.setContent()
|
|
475
539
|
this.setInputEvents()
|
|
@@ -21,6 +21,13 @@ export default {
|
|
|
21
21
|
math: 'Math',
|
|
22
22
|
minimize: 'Minimize',
|
|
23
23
|
read_text_aloud: 'Read Text aloud',
|
|
24
|
+
revise_text: 'Revise text',
|
|
25
|
+
shorten: 'Shorten',
|
|
26
|
+
rephrase: 'Rephrase',
|
|
27
|
+
proofread: 'Proofread',
|
|
28
|
+
revision_error: 'Unable to revise text. Try selecting a smaller portion or edit manually.',
|
|
29
|
+
revision_protected_error:
|
|
30
|
+
'Select text outside of math, fill-in-the-blank, or glossary items before revising.',
|
|
24
31
|
heading_order_incorrect:
|
|
25
32
|
'Headings must be applied in sequential order: H2 should be followed by H3, H4, and so on',
|
|
26
33
|
wcag_guidelines: '(WCAG {0} guidelines)',
|
|
@@ -22,6 +22,14 @@ export default {
|
|
|
22
22
|
math: 'Matemáticas',
|
|
23
23
|
minimize: 'Minimizar',
|
|
24
24
|
read_text_aloud: 'Leer texto',
|
|
25
|
+
revise_text: 'Revisar texto',
|
|
26
|
+
shorten: 'Acortar',
|
|
27
|
+
rephrase: 'Reformular',
|
|
28
|
+
proofread: 'Corregir',
|
|
29
|
+
revision_error:
|
|
30
|
+
'No se pudo revisar el texto. Intenta seleccionar un fragmento más pequeño o edita manualmente.',
|
|
31
|
+
revision_protected_error:
|
|
32
|
+
'Selecciona texto fuera de elementos de matemáticas, rellenado o glosario antes de revisar.',
|
|
25
33
|
heading_order_incorrect:
|
|
26
34
|
'Los títulos deben aplicarse en orden secuencial: H2 debe ir seguido de H3, H4, etc.',
|
|
27
35
|
wcag_guidelines: '(Directrices WCAG {0})',
|
|
@@ -22,6 +22,14 @@ export default {
|
|
|
22
22
|
math: 'Matematik',
|
|
23
23
|
minimize: 'Minimera',
|
|
24
24
|
read_text_aloud: 'Läs texten högt',
|
|
25
|
+
revise_text: 'Revidera text',
|
|
26
|
+
shorten: 'Förkorta',
|
|
27
|
+
rephrase: 'Omformulera',
|
|
28
|
+
proofread: 'Korrekturläs',
|
|
29
|
+
revision_error:
|
|
30
|
+
'Det gick inte att revidera texten. Försök markera ett mindre avsnitt eller redigera manuellt.',
|
|
31
|
+
revision_protected_error:
|
|
32
|
+
'Markera text utanför matematik, lucktexter eller ordlistor innan du reviderar.',
|
|
25
33
|
heading_order_incorrect:
|
|
26
34
|
'Rubriker måste tillämpas i sekventiell ordning: H2 ska följas av H3, H4, och så vidare',
|
|
27
35
|
wcag_guidelines: '(WCAG {0} riktlinjer)',
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -18,7 +18,6 @@ import Image from './components/Content/Blocks/Image'
|
|
|
18
18
|
import UserUpload from './components/Content/Blocks/UserUpload'
|
|
19
19
|
import FileDownload from './components/Content/Blocks/FileDownload'
|
|
20
20
|
|
|
21
|
-
import GlossaryPage from './pages/glossary.vue'
|
|
22
21
|
import TinymcePlugin from './pages/plugins/tinymce/_plugin.vue'
|
|
23
22
|
|
|
24
23
|
import CourseGlossaryToolNav from './components/Navigation/Items/CourseGlossaryToolNav.vue'
|
|
@@ -40,7 +39,6 @@ import EmailSettings from './components/Settings/EmailSettings.vue'
|
|
|
40
39
|
import BlockQuoteSettigns from './components/Settings/BlockQuoteSettings.vue'
|
|
41
40
|
import HorizontalRuleSettings from './components/Settings/HorizontalRuleSettings.vue'
|
|
42
41
|
|
|
43
|
-
import UserUploadPage from './pages/userUpload.vue'
|
|
44
42
|
import GlossaryToolTip from './components/utils/glossary/GlossaryToolTip.vue'
|
|
45
43
|
import TextEditorSettings from './components/Settings/TextEditorSettings.vue'
|
|
46
44
|
import FillInTheBlanks from './components/utils/FillInBlank/FillInTheBlanksManager.vue'
|
|
@@ -71,22 +69,6 @@ export default {
|
|
|
71
69
|
},
|
|
72
70
|
i18n: locales.messages,
|
|
73
71
|
pages: [
|
|
74
|
-
{
|
|
75
|
-
page: 'user-uploads',
|
|
76
|
-
path: '/course/:course/section/:section/user-uploads',
|
|
77
|
-
i18n: 'menu.user-upload',
|
|
78
|
-
icon: 'mdi-cloud-upload',
|
|
79
|
-
name: 'PluginUserUploadPage',
|
|
80
|
-
template: UserUploadPage,
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
page: 'glossary',
|
|
84
|
-
path: '/course/:course/section/:section/glossary',
|
|
85
|
-
i18n: 'windward.core.shared.menu.course_glossary',
|
|
86
|
-
icon: 'mdi-comment-text-multiple',
|
|
87
|
-
name: 'CourseGlossaryPage',
|
|
88
|
-
template: GlossaryPage,
|
|
89
|
-
},
|
|
90
72
|
{
|
|
91
73
|
page: 'tinymce-plugin',
|
|
92
74
|
path: '/plugins/tinymce/:plugin',
|
|
@@ -116,32 +98,6 @@ export default {
|
|
|
116
98
|
},
|
|
117
99
|
],
|
|
118
100
|
menu: [
|
|
119
|
-
{
|
|
120
|
-
tag: 'core-user-upload-nav',
|
|
121
|
-
path: '/course/{course.id}/section/{section.id}/user-uploads',
|
|
122
|
-
icon: 'mdi-cloud-upload',
|
|
123
|
-
i18n: 'windward.core.components.navigation.user_upload.title',
|
|
124
|
-
context: ['course'],
|
|
125
|
-
display: ['menu'],
|
|
126
|
-
permissions: {
|
|
127
|
-
'windward.organization.course.file': {
|
|
128
|
-
writable: true,
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
tag: 'core-user-glossary-nav',
|
|
134
|
-
path: '/course/{course.id}/section/{section.id}/glossary',
|
|
135
|
-
icon: 'mdi-comment-text-multiple',
|
|
136
|
-
i18n: 'windward.core.shared.menu.course_glossary',
|
|
137
|
-
context: ['course'],
|
|
138
|
-
display: ['menu'],
|
|
139
|
-
permissions: {
|
|
140
|
-
'windward.organization.course.content': {
|
|
141
|
-
readable: true,
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
101
|
{
|
|
146
102
|
tag: 'core-ask-the-expert',
|
|
147
103
|
i18n: 'windward.core.shared.menu.ask_the_expert',
|
package/test/mocks.js
CHANGED