@windward/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc.js +11 -0
  3. package/.prettierrc +4 -0
  4. package/README.md +86 -0
  5. package/babel.config.js +1 -0
  6. package/components/Content/Blocks/Accordion.vue +133 -0
  7. package/components/Content/Blocks/ClickableIcons.vue +98 -0
  8. package/components/Content/Blocks/Feedback.vue +323 -0
  9. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionLikert.vue +95 -0
  10. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.vue +45 -0
  11. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionTrueFalse.vue +55 -0
  12. package/components/Content/Blocks/Image.vue +116 -0
  13. package/components/Content/Blocks/Math.vue +87 -0
  14. package/components/Content/Blocks/Tab.vue +89 -0
  15. package/components/Content/Blocks/Table.vue +68 -0
  16. package/components/Content/Blocks/UserUpload/DisplayUserFilesTable.vue +157 -0
  17. package/components/Content/Blocks/UserUpload/ManageDataTableUserFiles.vue +68 -0
  18. package/components/Content/Blocks/UserUpload.vue +240 -0
  19. package/components/Content/Blocks/Video.vue +245 -0
  20. package/components/Navigation/Items/CourseGlossaryToolNav.vue +39 -0
  21. package/components/Navigation/Items/GlossaryNav.vue +32 -0
  22. package/components/Navigation/Items/UserUploadNav.vue +35 -0
  23. package/components/Settings/AccordionSettings.vue +153 -0
  24. package/components/Settings/ClickableIconsSettings.vue +189 -0
  25. package/components/Settings/FeedbackSettings.vue +92 -0
  26. package/components/Settings/ImageSettings.vue +124 -0
  27. package/components/Settings/MathSettings.vue +81 -0
  28. package/components/Settings/TabSettings.vue +139 -0
  29. package/components/Settings/TextEditorSettings.vue +249 -0
  30. package/components/Settings/UserUploadSettings.vue +151 -0
  31. package/components/Settings/VideoSettings.vue +699 -0
  32. package/components/utils/ContentViewer.vue +69 -0
  33. package/components/utils/MathExpressionEditor.vue +294 -0
  34. package/components/utils/MathLiveWrapper.vue +86 -0
  35. package/components/utils/TinyMCEWrapper.vue +103 -0
  36. package/components/utils/glossary/CourseGlossary.vue +284 -0
  37. package/components/utils/glossary/CourseGlossaryForm.vue +106 -0
  38. package/components/utils/glossary/GlossaryToolTip.vue +87 -0
  39. package/config/tinymce.config.js +136 -0
  40. package/helpers/GlossaryHelper.ts +137 -0
  41. package/helpers/GlossaryTerm.ts +31 -0
  42. package/helpers/MathHelper.ts +236 -0
  43. package/helpers/tinymce/plugin.ts +83 -0
  44. package/i18n/en-US/components/content/blocks/feedback.ts +28 -0
  45. package/i18n/en-US/components/content/blocks/image.ts +5 -0
  46. package/i18n/en-US/components/content/blocks/index.ts +15 -0
  47. package/i18n/en-US/components/content/blocks/tab.ts +4 -0
  48. package/i18n/en-US/components/content/blocks/table.ts +4 -0
  49. package/i18n/en-US/components/content/blocks/user_upload.ts +12 -0
  50. package/i18n/en-US/components/content/blocks/video.ts +53 -0
  51. package/i18n/en-US/components/content/index.ts +5 -0
  52. package/i18n/en-US/components/index.ts +12 -0
  53. package/i18n/en-US/components/navigation/image.ts +4 -0
  54. package/i18n/en-US/components/navigation/index.ts +7 -0
  55. package/i18n/en-US/components/navigation/user_upload.ts +3 -0
  56. package/i18n/en-US/components/settings/clickable_icon.ts +9 -0
  57. package/i18n/en-US/components/settings/image.ts +1 -0
  58. package/i18n/en-US/components/settings/index.ts +13 -0
  59. package/i18n/en-US/components/settings/text_editor.ts +7 -0
  60. package/i18n/en-US/components/settings/user_upload.ts +11 -0
  61. package/i18n/en-US/components/settings/video.ts +13 -0
  62. package/i18n/en-US/components/utils/index.ts +5 -0
  63. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +7 -0
  64. package/i18n/en-US/index.ts +16 -0
  65. package/i18n/en-US/modules/index.ts +5 -0
  66. package/i18n/en-US/pages/glossary.ts +7 -0
  67. package/i18n/en-US/pages/index.ts +7 -0
  68. package/i18n/en-US/pages/user_upload.ts +3 -0
  69. package/i18n/en-US/shared/content_blocks.ts +20 -0
  70. package/i18n/en-US/shared/index.ts +11 -0
  71. package/i18n/en-US/shared/menu.ts +3 -0
  72. package/i18n/en-US/shared/permission.ts +15 -0
  73. package/i18n/en-US/shared/settings.ts +15 -0
  74. package/index.js +15 -0
  75. package/jest.config.js +15 -0
  76. package/models/SurveyResult.ts +8 -0
  77. package/models/SurveyTemplate.ts +8 -0
  78. package/models/UserFileAsset.ts +12 -0
  79. package/package.json +48 -0
  80. package/pages/glossary.vue +31 -0
  81. package/pages/userUpload.vue +204 -0
  82. package/plugin.js +299 -0
  83. package/test/Components/Content/Blocks/Accordion.spec.js +21 -0
  84. package/test/Components/Content/Blocks/ClickableIcons.spec.js +21 -0
  85. package/test/Components/Content/Blocks/Feedback.spec.js +31 -0
  86. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionLikert.spec.js +23 -0
  87. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.spec.js +23 -0
  88. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionTrueFalse.spec.js +23 -0
  89. package/test/Components/Content/Blocks/Image.spec.js +34 -0
  90. package/test/Components/Content/Blocks/Math.spec.js +34 -0
  91. package/test/Components/Content/Blocks/Tab.spec.js +20 -0
  92. package/test/Components/Content/Blocks/Table.spec.js +21 -0
  93. package/test/Components/Content/Blocks/UserUpload.spec.js +25 -0
  94. package/test/Components/Content/Blocks/Video.spec.js +112 -0
  95. package/test/Components/Settings/AccordionSettings.spec.js +45 -0
  96. package/test/Components/Settings/ClickableIconsSettings.spec.js +20 -0
  97. package/test/Components/Settings/FeedbackSettings.spec.js +20 -0
  98. package/test/Components/Settings/ImageSettings.spec.js +20 -0
  99. package/test/Components/Settings/MathSettings.spec.js +20 -0
  100. package/test/Components/Settings/TabSettings.spec.js +45 -0
  101. package/test/Components/Settings/UserUploadSettings.spec.js +20 -0
  102. package/test/__mocks__/componentsMock.js +83 -0
  103. package/test/__mocks__/contentBlockMock.js +119 -0
  104. package/test/__mocks__/contentSettingsMock.js +54 -0
  105. package/test/__mocks__/fileMock.js +1 -0
  106. package/test/__mocks__/helpersMock.js +53 -0
  107. package/test/__mocks__/modelMock.js +82 -0
  108. package/test/__mocks__/styleMock.js +1 -0
  109. package/test/helpers/GlossaryHelper.spec.js +227 -0
  110. package/test/helpers/MathHelper.spec.js +128 -0
  111. package/test/mocks.js +140 -0
  112. package/tsconfig.json +15 -0
  113. package/utils/index.js +18 -0
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <div>
3
+ <h2 class="pb-4">
4
+ {{ $t('plugin.core.components.content.blocks.feedback.preset') }}
5
+ </h2>
6
+ <v-row>
7
+ <v-col v-for="preset in templates" :key="preset.id" cols="6">
8
+ <v-tooltip top>
9
+ <template #activator="{ on, attrs }">
10
+ <v-btn
11
+ class="preset-btn text-sm-body-2 text-none"
12
+ color="primary"
13
+ outlined
14
+ v-bind="attrs"
15
+ v-on="on"
16
+ @click="onPresetChoose(preset)"
17
+ >
18
+ <span>
19
+ {{ $t(preset.name) }}
20
+ </span>
21
+ </v-btn>
22
+ </template>
23
+ <span> {{ $t(preset.description) }} </span>
24
+ </v-tooltip>
25
+ </v-col>
26
+ </v-row>
27
+ </div>
28
+ </template>
29
+
30
+ <script>
31
+ import _ from 'lodash'
32
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
33
+ import { mapGetters } from 'vuex'
34
+
35
+ import SurveyTemplate from '../../models/SurveyTemplate'
36
+ import Enrollment from '~/models/Enrollment'
37
+ import ContentBlock from '~/models/ContentBlock'
38
+
39
+ export default {
40
+ name: 'FeedbackSettings',
41
+ extends: BaseContentSettings,
42
+ components: {},
43
+ beforeMount() {
44
+ if (_.isEmpty(this.block)) {
45
+ this.block = {}
46
+ }
47
+ if (_.isEmpty(this.block.metadata)) {
48
+ this.block.metadata = {}
49
+ }
50
+ if (_.isEmpty(this.block.metadata.config)) {
51
+ this.block.metadata.config = {}
52
+ }
53
+ if (_.isEmpty(this.block.metadata.config.definition)) {
54
+ this.block.metadata.config.definition = {}
55
+ }
56
+ this.block.body = 'feedback'
57
+ },
58
+ data() {
59
+ return {
60
+ templates: '',
61
+ }
62
+ },
63
+ computed: {
64
+ ...mapGetters({
65
+ enrollment: 'enrollment/get',
66
+ course: 'course/get',
67
+ }),
68
+ },
69
+ mounted() {
70
+ this.getTemplates()
71
+ },
72
+ methods: {
73
+ async getTemplates() {
74
+ if (this.enrollment.id && this.block.id) {
75
+ this.templates = await new SurveyTemplate()
76
+ .for(
77
+ new Enrollment({ id: this.enrollment.id }),
78
+ new ContentBlock({ id: this.block.id })
79
+ )
80
+ .get()
81
+ }
82
+ },
83
+ onPresetChoose(preset) {
84
+ preset.metadata.definition.forEach((element) => {
85
+ element.response = ' '
86
+ })
87
+ this.block.metadata.config.definition = preset
88
+ },
89
+ },
90
+ }
91
+ </script>
92
+ <style></style>
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <v-container>
3
+ <ContentBlockAsset
4
+ mimes="image/jpeg,image/png,image/gif"
5
+ @click:file="onFileSelect"
6
+ class="mb-4"
7
+ >
8
+ <template #title>
9
+ {{ $t('windward.core.components.content.blocks.image.title') }}
10
+ </template>
11
+ <template #description>
12
+ {{
13
+ $t(
14
+ 'windward.core.components.content.blocks.image.description'
15
+ )
16
+ }}
17
+ </template>
18
+ </ContentBlockAsset>
19
+
20
+ <v-form>
21
+ <v-text-field
22
+ v-model="block.metadata.config.alt"
23
+ :label="
24
+ $t('windward.core.components.navigation.image.default_alt')
25
+ "
26
+ :rules="validation.textRules"
27
+ ></v-text-field>
28
+ <h3 class="pb-2">
29
+ {{
30
+ $t(
31
+ 'windward.core.components.navigation.image.default_aria_described'
32
+ )
33
+ }}
34
+ </h3>
35
+ <TextEditor
36
+ v-model="block.metadata.config.aria_describedby"
37
+ ></TextEditor>
38
+ </v-form>
39
+ </v-container>
40
+ </template>
41
+
42
+ <script>
43
+ import _ from 'lodash'
44
+ import TextEditor from '~/components/Text/TextEditor.vue'
45
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
46
+ import ContentBlockAsset from '~/components/Content/ContentBlockAsset.vue'
47
+
48
+ export default {
49
+ name: 'ImageSettings',
50
+ extends: BaseContentSettings,
51
+ components: { ContentBlockAsset, TextEditor },
52
+ props: {
53
+ settings: { type: Object, required: false, default: null },
54
+ context: { type: String, required: false, default: 'block' },
55
+ },
56
+ beforeMount() {
57
+ if (_.isEmpty(this.block)) {
58
+ this.block = {}
59
+ }
60
+ if (_.isEmpty(this.block.body)) {
61
+ this.block.body = ''
62
+ }
63
+ if (_.isEmpty(this.block.metadata)) {
64
+ this.block.metadata = {}
65
+ }
66
+ if (_.isEmpty(this.block.metadata.config)) {
67
+ this.block.metadata.config = {}
68
+ }
69
+ if (_.isEmpty(this.block.metadata.config.alt)) {
70
+ this.block.metadata.config.alt = ''
71
+ }
72
+ if (_.isEmpty(this.block.metadata.config.aria_describedby)) {
73
+ this.block.metadata.config.aria_describedby = ''
74
+ }
75
+ },
76
+ data() {
77
+ return {
78
+ imageSettings: {
79
+ // Default values
80
+ alt_text: '',
81
+ aria_described: '',
82
+ release_results: 'submitted',
83
+ },
84
+ validation: {
85
+ textRules: [
86
+ (v) => !!v || this.$t('shared.forms.errors.required'),
87
+ ],
88
+ },
89
+ }
90
+ },
91
+ watch: {},
92
+ mounted() {},
93
+ methods: {
94
+ onFileSelect(file) {
95
+ // file = null when you remove a file
96
+ if (_.isEmpty(file)) {
97
+ this.block.body = ''
98
+ } else {
99
+ this.block.body = file.asset.public_url
100
+
101
+ //Assign height and width for skeleton loader
102
+ if (!_.isEmpty(file.asset.metadata.props)) {
103
+ this.block.metadata.config.height =
104
+ file.asset.metadata.props['height']
105
+ this.block.metadata.config.width =
106
+ file.asset.metadata.props['width']
107
+ }
108
+ // Assign any alt text from the filemanager file
109
+ this.block.metadata.config.alt = _.get(
110
+ file,
111
+ 'asset.metadata.props.alt',
112
+ ''
113
+ )
114
+
115
+ this.block.metadata.config.aria_describedby = _.get(
116
+ file,
117
+ 'asset.metadata.props.aria_describedby',
118
+ ''
119
+ )
120
+ }
121
+ },
122
+ },
123
+ }
124
+ </script>
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <div>
3
+ <br />
4
+ <v-btn @click="onToggleExpand" class="mb-2">
5
+ <v-icon v-if="!block.metadata.config.expand"
6
+ >mdi-arrow-expand-all</v-icon
7
+ >
8
+ <v-icon v-if="block.metadata.config.expand">
9
+ mdi-arrow-collapse-all
10
+ </v-icon>
11
+ </v-btn>
12
+ <math-expression-editor
13
+ v-if="!block.metadata.config.expand"
14
+ :key="key"
15
+ :shrinkFont="true"
16
+ v-model="block.metadata.config.formula"
17
+ mode="standalone"
18
+ :value="block.metadata.config.formula"
19
+ ></math-expression-editor>
20
+ <br />
21
+ </div>
22
+ </template>
23
+
24
+ <script>
25
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
26
+ import MathExpressionEditor from '../utils/MathExpressionEditor.vue'
27
+ import _ from 'lodash'
28
+ import Crypto from '~/helpers/Crypto'
29
+
30
+ export default {
31
+ name: 'MathSettings',
32
+ components: { MathExpressionEditor },
33
+ extends: BaseContentSettings,
34
+ beforeMount() {
35
+ if (_.isEmpty(this.block)) {
36
+ this.block = {}
37
+ }
38
+ if (_.isEmpty(this.block.body)) {
39
+ this.block.body = 'Math Editor'
40
+ }
41
+ if (_.isEmpty(this.block.metadata)) {
42
+ this.block.metadata = {}
43
+ }
44
+ if (_.isEmpty(this.block.metadata.config)) {
45
+ this.block.metadata.config = {}
46
+ }
47
+ if (_.isEmpty(this.block.metadata.config.formula)) {
48
+ this.block.metadata.config.formula = ''
49
+ }
50
+ if (_.isEmpty(this.block.metadata.config.expand)) {
51
+ this.block.metadata.config.expand = false
52
+ }
53
+ },
54
+ data() {
55
+ return {
56
+ key: '0',
57
+ }
58
+ },
59
+ mounted() {},
60
+ beforeDestroy() {
61
+ if (this.debouncer) {
62
+ clearTimeout(this.debouncer)
63
+ }
64
+ },
65
+ watch: {
66
+ value(newValue) {
67
+ if (newValue.metadata.config.expand === true) {
68
+ this.key = Crypto.id()
69
+ }
70
+ },
71
+ },
72
+ methods: {
73
+ onToggleExpand() {
74
+ this.key = Crypto.id()
75
+ return (this.block.metadata.config.expand =
76
+ !this.block.metadata.config.expand)
77
+ },
78
+ },
79
+ }
80
+ </script>
81
+ <style scoped></style>
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <div>
3
+ <v-btn color="primary" @click="onAddElement" class="fullWidth">
4
+ <v-icon>mdi-plus</v-icon>
5
+ {{ $t('windward.core.components.content.blocks.tab.add_tab') }}
6
+ </v-btn>
7
+ <v-expansion-panels flat>
8
+ <v-expansion-panel
9
+ v-for="(item, itemIndex) in block.metadata.config.items"
10
+ :key="itemIndex"
11
+ class="elevation-0"
12
+ >
13
+ <v-expansion-panel-header>{{
14
+ 'Tab ' + (itemIndex + 1)
15
+ }}</v-expansion-panel-header>
16
+ <v-expansion-panel-content :key="expansionPanelKey">
17
+ <v-text-field
18
+ v-model="
19
+ block.metadata.config.items[itemIndex].tabHeader
20
+ "
21
+ :placeholder="'item ' + (itemIndex + 1)"
22
+ ></v-text-field>
23
+ <v-btn @click="onToggleExpand(item)" class="mb-3">
24
+ <v-icon
25
+ v-if="
26
+ !block.metadata.config.items[itemIndex].expand
27
+ "
28
+ >mdi-arrow-expand-all</v-icon
29
+ >
30
+ <v-icon
31
+ v-if="block.metadata.config.items[itemIndex].expand"
32
+ >
33
+ mdi-arrow-collapse-all
34
+ </v-icon>
35
+ </v-btn>
36
+ <br />
37
+ <TextEditor
38
+ :api_key="api_key"
39
+ v-model="block.metadata.config.items[itemIndex].content"
40
+ v-show="!block.metadata.config.items[itemIndex].expand"
41
+ ></TextEditor>
42
+ <br />
43
+ <v-btn
44
+ color="primary"
45
+ @click="onRemoveElement(itemIndex)"
46
+ class="fullWidth"
47
+ >
48
+ <v-icon>mdi-minus</v-icon>
49
+ {{
50
+ $t(
51
+ 'windward.core.components.content.blocks.tab.delete_tab'
52
+ )
53
+ }}
54
+ </v-btn>
55
+ </v-expansion-panel-content>
56
+ </v-expansion-panel>
57
+ </v-expansion-panels>
58
+ </div>
59
+ </template>
60
+
61
+ <script>
62
+ import _ from 'lodash'
63
+ import Crypto from '~/helpers/Crypto'
64
+ import TextEditor from '~/components/Text/TextEditor.vue'
65
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
66
+
67
+ export default {
68
+ name: 'TabSettings',
69
+ components: { TextEditor },
70
+ extends: BaseContentSettings,
71
+ beforeMount() {
72
+ if (_.isEmpty(this.block)) {
73
+ this.block = {}
74
+ }
75
+ if (_.isEmpty(this.block.body)) {
76
+ this.block.body = ''
77
+ }
78
+ if (_.isEmpty(this.block.metadata)) {
79
+ this.block.metadata = {}
80
+ }
81
+ if (_.isEmpty(this.block.metadata.config)) {
82
+ this.block.metadata.config = {}
83
+ }
84
+ if (_.isEmpty(this.block.metadata.config.items)) {
85
+ const defaultObject = {
86
+ tabHeader: '',
87
+ expand: false,
88
+ content: '',
89
+ }
90
+ this.block.metadata.config.items = []
91
+ this.block.metadata.config.items.push(defaultObject)
92
+ }
93
+ this.block.body = 'tab'
94
+ },
95
+ data() {
96
+ return {
97
+ expansionPanelKey: '0',
98
+ api_key: process.env.TINY_MCE_API_KEY,
99
+ }
100
+ },
101
+ mounted() {
102
+ if (this.block.metadata.config.items.length <= 0) {
103
+ this.onAddElement()
104
+ }
105
+ },
106
+ beforeDestroy() {
107
+ if (this.debouncer) {
108
+ clearTimeout(this.debouncer)
109
+ }
110
+ },
111
+
112
+ methods: {
113
+ onAddElement() {
114
+ const defaultObject = {
115
+ tabHeader: '',
116
+ expand: false,
117
+ content: '',
118
+ }
119
+ this.block.metadata.config.items.push(defaultObject)
120
+ },
121
+ onRemoveElement(index) {
122
+ this.block.metadata.config.items.splice(index, 1)
123
+ this.expansionPanelKey = Crypto.id()
124
+ },
125
+ onToggleExpand(item) {
126
+ this.expansionPanelKey = Crypto.id()
127
+ return (item.expand = !item.expand)
128
+ },
129
+ },
130
+ }
131
+ </script>
132
+ <style scoped>
133
+ .v-progress-circular {
134
+ margin: 1rem;
135
+ }
136
+ .fullWidth {
137
+ width: 100%;
138
+ }
139
+ </style>
@@ -0,0 +1,249 @@
1
+ <template>
2
+ <div>
3
+ <br />
4
+ <v-card elevation="0">
5
+ <v-btn-toggle v-model="settingSelector" multiple>
6
+ <v-btn>
7
+ <v-icon>mdi-comment-text-multiple</v-icon>
8
+ {{
9
+ $t(
10
+ 'windward.core.components.settings.text_editor.glossary'
11
+ )
12
+ }}
13
+ </v-btn>
14
+ <v-btn>
15
+ <v-icon> mdi-text-long</v-icon>
16
+ {{
17
+ $t(
18
+ 'windward.core.components.settings.text_editor.Text_editor'
19
+ )
20
+ }}
21
+ </v-btn>
22
+ <v-btn
23
+ v-if="settingSelector.includes(1)"
24
+ @click="
25
+ block.metadata.config.expand =
26
+ !block.metadata.config.expand
27
+ "
28
+ >
29
+ <v-icon v-if="!block.metadata.config.expand"
30
+ >mdi-arrow-expand-all</v-icon
31
+ >
32
+ <v-icon v-if="block.metadata.config.expand">
33
+ mdi-arrow-collapse-all
34
+ </v-icon>
35
+ </v-btn>
36
+ </v-btn-toggle>
37
+ <br />
38
+ </v-card>
39
+ <div v-show="settingSelector.includes(0)" class="pt-4">
40
+ <br />
41
+ <v-card elevation="0" outlined v-if="verifiedTerms.length > 0">
42
+ <v-card-title outlined class="text-capitalize">
43
+ {{
44
+ $t(
45
+ 'windward.core.components.settings.text_editor.verified_terms'
46
+ )
47
+ }}
48
+ </v-card-title>
49
+ <v-card-text>
50
+ <v-chip
51
+ v-for="(verified, index) in verifiedTerms"
52
+ :key="index"
53
+ class="ma-2"
54
+ close
55
+ color="success"
56
+ close-icon="mdi-pencil"
57
+ @click:close="editTerm(verified)"
58
+ >
59
+ {{ verified.term }}
60
+ </v-chip>
61
+ </v-card-text>
62
+ </v-card>
63
+ <v-card elevation="0" outlined v-if="unVerifiedTerms.length > 0">
64
+ <v-card-title outlined class="text-capitalize">
65
+ {{
66
+ $t(
67
+ 'windward.core.components.settings.text_editor.unverified_terms'
68
+ )
69
+ }}
70
+ </v-card-title>
71
+ <v-card-text>
72
+ <v-chip
73
+ v-for="(unVerified, index) in unVerifiedTerms"
74
+ :key="index"
75
+ class="ma-2"
76
+ close
77
+ color="error"
78
+ close-icon="mdi-content-save-plus-outline"
79
+ @click:close="addGlossaryTerm(unVerified)"
80
+ >
81
+ {{ unVerified.term }}
82
+ </v-chip>
83
+ </v-card-text>
84
+ </v-card>
85
+ <v-card
86
+ elevation="0"
87
+ outlined
88
+ v-if="
89
+ verifiedTerms.length === 0 && unVerifiedTerms.length === 0
90
+ "
91
+ ><v-card-text class="text-capitalize font-weight-bold">
92
+ {{
93
+ $t(
94
+ 'windward.core.components.settings.text_editor.no_glossary'
95
+ )
96
+ }}
97
+ </v-card-text></v-card
98
+ >
99
+ </div>
100
+ <br />
101
+ <text-editor
102
+ v-model="block.body"
103
+ v-show="
104
+ settingSelector.includes(1) && !block.metadata.config.expand
105
+ "
106
+ ></text-editor>
107
+ <v-skeleton-loader
108
+ v-bind="attrs"
109
+ type=" table-row-divider, list-item, divider, list-item, divider, image,image"
110
+ v-show="settingSelector.includes(1) && block.metadata.config.expand"
111
+ ></v-skeleton-loader>
112
+ <Dialog
113
+ v-model="dialog"
114
+ color="primary"
115
+ max-width="600px"
116
+ action-save
117
+ :trigger="false"
118
+ @click:save="save"
119
+ @click:outside="close"
120
+ @click:close="close"
121
+ @keydown.esc="close"
122
+ >
123
+ <template #title> {{ formTitle }} </template>
124
+ <template #form="{ on, attrs }">
125
+ <course-glossary-form
126
+ v-model="selectedTerm"
127
+ :glossary="glossary"
128
+ :edit-mode="glossaryEdit"
129
+ v-bind="attrs"
130
+ v-on="on"
131
+ />
132
+ </template>
133
+ </Dialog>
134
+ </div>
135
+ </template>
136
+
137
+ <script>
138
+ import { mapGetters, mapMutations } from 'vuex'
139
+ import GlossaryHelper from '../../helpers/GlossaryHelper'
140
+ import Course from '~/models/Course'
141
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
142
+ import TextEditor from '~/components/Text/TextEditor.vue'
143
+ import CourseGlossaryForm from '../utils/glossary/CourseGlossaryForm.vue'
144
+ export default {
145
+ name: 'TextEditorSettings',
146
+ extends: BaseContentSettings,
147
+ components: {
148
+ TextEditor,
149
+ CourseGlossaryForm,
150
+ },
151
+ data() {
152
+ return {
153
+ dialog: false,
154
+ selectedTerm: {},
155
+ formTitle: '',
156
+ glossaryEdit: false,
157
+ settingSelector: [0, 1],
158
+ attrs: {
159
+ class: 'mb-6',
160
+ boilerplate: true,
161
+ elevation: 0,
162
+ },
163
+ }
164
+ },
165
+ computed: {
166
+ ...mapGetters({
167
+ course: 'course/get',
168
+ }),
169
+ ...mapMutations({
170
+ saveCourse: 'course/set',
171
+ }),
172
+ glossary() {
173
+ return _.isObject(this.course.metadata) &&
174
+ _.isArray(this.course.metadata.glossary)
175
+ ? this.course.metadata.glossary
176
+ : []
177
+ },
178
+ verifiedTerms() {
179
+ return GlossaryHelper.getContentVerifiedGlossaryTerms(
180
+ this.block.body,
181
+ this.glossary
182
+ )
183
+ },
184
+ unVerifiedTerms() {
185
+ return GlossaryHelper.getContentUnVerifiedGlossaryTerms(
186
+ this.block.body,
187
+ this.glossary
188
+ )
189
+ },
190
+ },
191
+ mounted() {
192
+ this.setConfig({ expand: false })
193
+ },
194
+ methods: {
195
+ async save() {
196
+ let currentGlossary = _.cloneDeep(this.glossary)
197
+ let currentItemIndex = -1
198
+ currentGlossary.filter((item, index) => {
199
+ if (item.term === this.selectedTerm.term) {
200
+ currentItemIndex = index
201
+ return item
202
+ }
203
+ })
204
+ if (currentItemIndex > -1) {
205
+ currentGlossary[currentItemIndex] = this.selectedTerm
206
+ } else {
207
+ currentGlossary.push(this.selectedTerm)
208
+ }
209
+ const course = new Course(this.course)
210
+ if (!_.isSet(course.metadata)) {
211
+ course.metadata = {}
212
+ course.metadata.glossary = {}
213
+ }
214
+ if (!_.isSet(course.metadata.glossary)) {
215
+ course.metadata.glossary = currentGlossary
216
+ }
217
+ const updatedCourse = await course.save()
218
+ this.$store.commit('course/set', updatedCourse)
219
+ this.$toast.success(this.$t('shared.forms.saved'))
220
+ },
221
+ editTerm(term) {
222
+ this.selectedTerm = term
223
+
224
+ this.formTitle =
225
+ this.$t('shared.forms.edit') +
226
+ ' ' +
227
+ this.$t('pages.glossary.page_glossary.term')
228
+ this.glossaryEdit = true
229
+ this.dialog = true
230
+ },
231
+ addGlossaryTerm(term) {
232
+ this.selectedTerm = term
233
+
234
+ this.formTitle =
235
+ this.$t('shared.forms.add') +
236
+ ' ' +
237
+ this.$t('pages.glossary.page_glossary.term')
238
+ this.glossaryEdit = false
239
+ this.dialog = true
240
+ },
241
+ close() {
242
+ this.glossaryEdit = false
243
+ this.dialog = false
244
+ },
245
+ },
246
+ }
247
+ </script>
248
+
249
+ <style scoped></style>