@windward/core 0.0.7 → 0.0.9

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 (80) hide show
  1. package/components/Content/Blocks/ClickableIcons.vue +128 -40
  2. package/components/Content/Blocks/Image.vue +37 -10
  3. package/components/Content/Blocks/OpenResponse.vue +32 -10
  4. package/components/Content/Blocks/OpenResponseCollate.vue +69 -42
  5. package/components/Content/Blocks/ScenarioChoice.vue +262 -0
  6. package/components/Content/Blocks/Tab.vue +2 -7
  7. package/components/Settings/AccordionSettings.vue +97 -74
  8. package/components/Settings/ClickableIconsSettings.vue +101 -86
  9. package/components/Settings/ImageSettings.vue +10 -0
  10. package/components/Settings/OpenResponseCollateSettings.vue +9 -8
  11. package/components/Settings/ScenarioChoiceSettings.vue +329 -0
  12. package/components/Settings/TabSettings.vue +75 -61
  13. package/components/Settings/TextEditorSettings.vue +2 -3
  14. package/components/utils/FillInBlank/FillInBlankInput.vue +4 -1
  15. package/components/utils/TinyMCEWrapper.vue +11 -4
  16. package/components/utils/assets/tinymce/css/content.scss +1 -1
  17. package/helpers/FillInBlankHelper.ts +0 -2
  18. package/helpers/tinymce/plugin.ts +1 -1
  19. package/i18n/en-US/components/content/blocks/index.ts +2 -2
  20. package/i18n/en-US/components/content/blocks/open_response_collate.ts +1 -0
  21. package/i18n/en-US/components/content/blocks/scenario_choice.ts +5 -0
  22. package/i18n/en-US/components/settings/accordion.ts +5 -0
  23. package/i18n/en-US/components/settings/clickable_icon.ts +8 -0
  24. package/i18n/en-US/components/settings/image.ts +3 -1
  25. package/i18n/en-US/components/settings/index.ts +6 -0
  26. package/i18n/en-US/components/settings/scenario_choice.ts +19 -0
  27. package/i18n/en-US/components/settings/tab.ts +7 -0
  28. package/i18n/en-US/components/utils/FillInBlank/FillInBlankInput.ts +1 -1
  29. package/i18n/en-US/shared/content_blocks.ts +1 -0
  30. package/i18n/en-US/shared/settings.ts +2 -0
  31. package/i18n/es-ES/components/content/blocks/feedback.ts +2 -0
  32. package/i18n/es-ES/components/content/blocks/index.ts +2 -2
  33. package/i18n/es-ES/components/content/blocks/open_response_collate.ts +1 -0
  34. package/i18n/es-ES/components/content/blocks/scenario_choice.ts +6 -0
  35. package/i18n/es-ES/components/navigation/index.ts +2 -0
  36. package/i18n/es-ES/components/settings/accordion.ts +5 -0
  37. package/i18n/es-ES/components/settings/clickable_icon.ts +8 -0
  38. package/i18n/es-ES/components/settings/image.ts +3 -1
  39. package/i18n/es-ES/components/settings/index.ts +6 -0
  40. package/i18n/es-ES/components/settings/scenario_choice.ts +19 -0
  41. package/i18n/es-ES/components/{content/blocks → settings}/tab.ts +3 -0
  42. package/i18n/es-ES/components/utils/FillInBlank/FillInBlankInput.ts +13 -0
  43. package/i18n/es-ES/components/utils/FillInBlank/FillInTheBlanksManager.ts +11 -0
  44. package/i18n/es-ES/components/utils/FillInBlank/index.ts +6 -0
  45. package/i18n/es-ES/components/utils/index.ts +2 -0
  46. package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +1 -0
  47. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  48. package/i18n/es-ES/shared/menu.ts +1 -0
  49. package/i18n/es-ES/shared/settings.ts +2 -0
  50. package/i18n/index.ts +11 -0
  51. package/i18n/sv-SE/components/content/blocks/feedback.ts +2 -0
  52. package/i18n/sv-SE/components/content/blocks/index.ts +2 -2
  53. package/i18n/sv-SE/components/content/blocks/open_response_collate.ts +1 -0
  54. package/i18n/sv-SE/components/content/blocks/scenario_choice.ts +5 -0
  55. package/i18n/sv-SE/components/navigation/index.ts +2 -0
  56. package/i18n/sv-SE/components/settings/accordion.ts +5 -0
  57. package/i18n/sv-SE/components/settings/clickable_icon.ts +8 -0
  58. package/i18n/sv-SE/components/settings/image.ts +3 -1
  59. package/i18n/sv-SE/components/settings/index.ts +6 -0
  60. package/i18n/sv-SE/components/settings/scenario_choice.ts +19 -0
  61. package/i18n/sv-SE/components/{content/blocks → settings}/tab.ts +3 -0
  62. package/i18n/sv-SE/components/utils/FillInBlank/FillInBlankInput.ts +13 -0
  63. package/i18n/sv-SE/components/utils/FillInBlank/FillInTheBlanksManager.ts +11 -0
  64. package/i18n/sv-SE/components/utils/FillInBlank/index.ts +6 -0
  65. package/i18n/sv-SE/components/utils/index.ts +2 -0
  66. package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +1 -0
  67. package/i18n/sv-SE/shared/content_blocks.ts +1 -0
  68. package/i18n/sv-SE/shared/menu.ts +1 -0
  69. package/i18n/sv-SE/shared/settings.ts +2 -0
  70. package/package.json +2 -1
  71. package/plugin.js +24 -5
  72. package/test/Components/Content/Blocks/ScenarioChoice.spec.js +21 -0
  73. package/test/Components/Settings/ClickableIconsSettings.spec.js +1 -1
  74. package/test/Components/Settings/ScenarioChoiceSettings.spec.js +20 -0
  75. package/test/Feature/LocaleKeys.spec.js +9 -0
  76. package/test/__mocks__/componentsMock.js +24 -0
  77. package/test/__mocks__/helpersMock.js +3 -0
  78. package/test/__mocks__/modelMock.js +4 -0
  79. package/test/locales.js +95 -0
  80. package/i18n/en-US/components/content/blocks/tab.ts +0 -4
@@ -0,0 +1,262 @@
1
+ <template>
2
+ <div>
3
+ <v-container>
4
+ <h3>{{ block.metadata.config.title }}</h3>
5
+ <h4>{{ block.metadata.config.description }}</h4>
6
+ <p>
7
+ {{
8
+ $t(
9
+ 'windward.core.components.content.blocks.scenario_choice.information'
10
+ )
11
+ }}
12
+ </p>
13
+ <div
14
+ v-if="choiceIndex !== null && block.metadata.config.show_reset"
15
+ class="text-right"
16
+ >
17
+ <v-btn color="primary" outlined @click="onClickReset">
18
+ {{
19
+ $t(
20
+ 'windward.core.components.content.blocks.scenario_choice.try_again'
21
+ )
22
+ }}
23
+ </v-btn>
24
+ </div>
25
+ </v-container>
26
+ <v-container>
27
+ <v-row
28
+ v-for="(item, itemIndex) in block.metadata.config.items"
29
+ :key="itemIndex"
30
+ no-gutters
31
+ :class="rowClass(item, itemIndex)"
32
+ >
33
+ <v-col cols="2" class="text-center">
34
+ <div
35
+ class="pt-8 pb-8 text-icon-container mb-4 mx-auto"
36
+ role="button"
37
+ @click="onClickItem(itemIndex)"
38
+ >
39
+ <span :class="iconClass(itemIndex)">{{
40
+ itemIcon(itemIndex)
41
+ }}</span>
42
+ </div>
43
+ <strong v-if="choiceIndex === itemIndex">
44
+ {{
45
+ $t(
46
+ 'windward.core.components.content.blocks.scenario_choice.selected_choice'
47
+ )
48
+ }}
49
+ </strong>
50
+ </v-col>
51
+ <v-col cols="10">
52
+ <h4
53
+ role="button"
54
+ class="mt-4"
55
+ @click="onClickItem(itemIndex)"
56
+ >
57
+ {{ item.title }}
58
+ </h4>
59
+
60
+ <v-expand-transition>
61
+ <div v-if="choiceIndex !== null">
62
+ <v-divider light class="my-4" />
63
+ <TextViewer v-model="item.body"></TextViewer>
64
+ <a
65
+ v-if="linkedPage !== null"
66
+ class="white--text text-decoration-underline"
67
+ @click="
68
+ onClickLink(linkedPage.course_content_id)
69
+ "
70
+ >
71
+ {{ linkedPage.text }}
72
+ </a>
73
+ </div>
74
+ </v-expand-transition>
75
+ </v-col>
76
+ </v-row>
77
+ </v-container>
78
+ </div>
79
+ </template>
80
+ <script>
81
+ import _ from 'lodash'
82
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
83
+ import TextViewer from '~/components/Text/TextViewer'
84
+
85
+ export default {
86
+ name: 'ClickableIcons',
87
+ components: {
88
+ TextViewer,
89
+ },
90
+ extends: BaseContentBlock,
91
+ data() {
92
+ return {
93
+ choiceIndex: null,
94
+ }
95
+ },
96
+ computed: {
97
+ rowClass() {
98
+ return (item, itemIndex) => {
99
+ let classes = 'option-container mb-4 pa-1 black--text '
100
+
101
+ // If an option was picked set the background to correct / incorrect
102
+ // Otherwise do the autocolor
103
+ if (this.choiceIndex !== null && item.correct) {
104
+ classes += 'success'
105
+ } else if (this.choiceIndex !== null && !item.correct) {
106
+ classes += 'error'
107
+ } else {
108
+ classes += this.itemColor(itemIndex)
109
+ }
110
+ return classes
111
+ }
112
+ },
113
+ iconClass() {
114
+ return (itemIndex) => {
115
+ let classes = 'text-icon '
116
+ // Add the appropriate color / modifiers to make the icon color
117
+ const color = this.itemColor(itemIndex).split(' ')
118
+ classes += color[0] + '--text text--' + color[1]
119
+
120
+ return classes
121
+ }
122
+ },
123
+ itemColor() {
124
+ return (itemIndex) => {
125
+ const colors = [
126
+ 'light-blue lighten-4',
127
+ 'light-green lighten-4',
128
+ 'yellow lighten-4',
129
+ 'orange lighten-3',
130
+ 'red lighten-3',
131
+ 'deep-purple lighten-3',
132
+ ]
133
+ let colorIndex = itemIndex
134
+ // If we exceed the above list of colors loop back around to the beginning
135
+ if (colorIndex >= colors.length) {
136
+ colorIndex =
137
+ colorIndex -
138
+ Math.floor(colorIndex / colors.length) * colors.length
139
+ }
140
+
141
+ return colors[colorIndex]
142
+ }
143
+ },
144
+ itemIcon() {
145
+ return (itemIndex) => {
146
+ if (isNaN(itemIndex) || itemIndex < 0) {
147
+ return 'ERR'
148
+ }
149
+ // Return a letter if the display style is letter (with super complicated logic)
150
+ // ... or return the index + 1 for number styles
151
+ if (this.block.metadata.config.display_style === 'letter') {
152
+ if (itemIndex <= 25) {
153
+ // 65 is where capitals start
154
+ return String.fromCharCode(65 + itemIndex)
155
+ } else {
156
+ // Calculate two character AA-ZZ or a max list length of 625 which we will never hit
157
+ // I'd be surprised if we ever get to AA tbh but I'm gonna support it just in case
158
+ const prependIndex = Math.floor(itemIndex / 26) - 1
159
+
160
+ return (
161
+ String.fromCharCode(65 + prependIndex) +
162
+ String.fromCharCode(
163
+ 65 + (itemIndex - 26 * (prependIndex + 1))
164
+ )
165
+ )
166
+ }
167
+ } else if (
168
+ this.block.metadata.config.display_style === 'number'
169
+ ) {
170
+ return itemIndex + 1
171
+ }
172
+ }
173
+ },
174
+ linkedPage() {
175
+ const isLinked =
176
+ !_.isEmpty(this.block.metadata.config.link_content_id) &&
177
+ !_.isEmpty(this.block.metadata.config.link_text)
178
+
179
+ if (isLinked) {
180
+ const flatTree = this.$ContentService.getFlatTree()
181
+ // Find the course_content_id that this content id is referencing
182
+ const pages = flatTree.filter((c) => {
183
+ return (
184
+ c.content_id ===
185
+ this.block.metadata.config.link_content_id
186
+ )
187
+ })
188
+
189
+ // We found it, so return it otherwise null
190
+ if (pages.length > 0) {
191
+ return {
192
+ text: this.block.metadata.config.link_text,
193
+ course_content_id: pages[0].id,
194
+ }
195
+ } else {
196
+ return null
197
+ }
198
+ } else {
199
+ return null
200
+ }
201
+ },
202
+ },
203
+ beforeMount() {
204
+ // Apply the default config
205
+ this.block.body = 'scenario choice'
206
+ if (_.isEmpty(this.block.metadata.config.items)) {
207
+ this.block.metadata.config.items = []
208
+ }
209
+ if (_.isEmpty(this.block.metadata.config.title)) {
210
+ this.block.metadata.config.title = ''
211
+ }
212
+ if (_.isEmpty(this.block.metadata.config.description)) {
213
+ this.block.metadata.config.description = ''
214
+ }
215
+ if (_.isEmpty(this.block.metadata.config.display_style)) {
216
+ this.block.metadata.config.display_style = 'letter'
217
+ }
218
+ if (_.isEmpty(this.block.metadata.config.link_content_id)) {
219
+ this.block.metadata.config.link_content_id = null
220
+ }
221
+ if (_.isEmpty(this.block.metadata.config.link_text)) {
222
+ this.block.metadata.config.link_text = null
223
+ }
224
+ if (!_.isBoolean(this.block.metadata.config.show_reset)) {
225
+ this.block.metadata.config.show_reset = false
226
+ }
227
+ },
228
+ methods: {
229
+ onClickReset() {
230
+ this.choiceIndex = null
231
+ },
232
+ onClickItem(itemIndex) {
233
+ // Only set the choice if it's null
234
+ if (this.choiceIndex === null) {
235
+ this.choiceIndex = itemIndex
236
+ }
237
+ },
238
+ onClickLink(id) {
239
+ this.$ContentService.set(id, { direct: true })
240
+ },
241
+ },
242
+ }
243
+ </script>
244
+ <style scoped>
245
+ .option-container {
246
+ border-radius: 1rem;
247
+ }
248
+ .text-icon-container {
249
+ background: #fff;
250
+ width: 5rem;
251
+ height: 5rem;
252
+ text-align: center;
253
+ line-height: 0;
254
+ margin: 1rem;
255
+ border-radius: 4rem;
256
+ }
257
+ .text-icon {
258
+ font-size: 4rem;
259
+ vertical-align: text-bottom;
260
+ filter: brightness(0.5);
261
+ }
262
+ </style>
@@ -5,7 +5,7 @@
5
5
  background-color="primary"
6
6
  v-model="block.metadata.config.tab"
7
7
  >
8
- <v-tabs-slider color="primary"></v-tabs-slider>
8
+ <v-tabs-slider></v-tabs-slider>
9
9
  <v-tab
10
10
  v-for="(tab, tabIndex) in block.metadata.config.items"
11
11
  :key="tabIndex"
@@ -24,12 +24,7 @@
24
24
  <v-container>
25
25
  <TextViewer
26
26
  v-if="!tabContent.expand"
27
- v-model="
28
- tabContent.content === '' ||
29
- tabContent.content === null
30
- ? 'Item ' + (tabContentIndex + 1)
31
- : tabContent.content
32
- "
27
+ v-model="tabContent.content"
33
28
  text-viewer
34
29
  ></TextViewer>
35
30
  <TextEditor
@@ -1,77 +1,95 @@
1
1
  <template>
2
2
  <div>
3
- <v-container class="pa-0">
4
- <v-btn
5
- color="primary"
6
- outlined
7
- @click="onAddElement"
8
- class="fullWidth"
9
- ><v-icon>mdi-plus</v-icon>{{ $t('shared.forms.add') }}</v-btn
10
- >
11
- <v-expansion-panels flat>
12
- <v-expansion-panel
13
- v-for="(item, itemIndex) in block.metadata.config.items"
14
- :key="itemIndex"
15
- class="elevation-0"
3
+ <v-form ref="form" v-model="valid" v-if="!loading">
4
+ <v-container class="pa-0">
5
+ <v-divider class="my-4 primary"></v-divider>
6
+ <p>
7
+ {{
8
+ $t('windward.core.components.settings.accordion.items')
9
+ }}
10
+ </p>
11
+ <SortableExpansionPanel
12
+ v-model="block.metadata.config.items"
13
+ @click:close="onRemoveElement($event)"
14
+ @change="onDragged"
16
15
  >
17
- <v-expansion-panel-header class="elevation-0">{{
18
- 'item ' + (itemIndex + 1)
19
- }}</v-expansion-panel-header>
20
- <v-expansion-panel-content
21
- class="elevation-0"
22
- :key="expansionPanelKey"
23
- >
24
- <v-text-field
25
- v-model="
26
- block.metadata.config.items[itemIndex].header
27
- "
28
- :label="'Item Title'"
29
- ></v-text-field>
30
- <v-btn
31
- @click="
32
- onToggleExpand(
33
- block.metadata.config.items[itemIndex]
34
- )
35
- "
36
- >
37
- <v-icon
38
- v-if="
39
- !block.metadata.config.items[itemIndex]
40
- .expand
16
+ <template #header="{ item }">{{
17
+ item.header
18
+ ? item.header
19
+ : $t(
20
+ 'plugin.games.components.settings.bucket_game.form.enter_text'
21
+ )
22
+ }}</template>
23
+ <template #body="{ index }">
24
+ <v-container :key="expansionPanelKey">
25
+ <v-text-field
26
+ outlined
27
+ :autofocus="true"
28
+ v-model="
29
+ block.metadata.config.items[index].header
41
30
  "
42
- >mdi-arrow-expand-all</v-icon
43
- >
44
- <v-icon
45
- v-if="
46
- block.metadata.config.items[itemIndex]
47
- .expand
31
+ :label="
32
+ $t(
33
+ 'windward.core.shared.settings.title.title'
34
+ )
35
+ "
36
+ ></v-text-field>
37
+ <v-btn
38
+ @click="
39
+ onToggleExpand(
40
+ block.metadata.config.items[index]
41
+ )
48
42
  "
49
43
  >
50
- mdi-arrow-collapse-all
51
- </v-icon>
52
- </v-btn>
53
- <TextEditor
54
- :api_key="api_key"
55
- v-show="
56
- !block.metadata.config.items[itemIndex].expand
57
- "
58
- v-model="
59
- block.metadata.config.items[itemIndex].content
60
- "
61
- ></TextEditor>
62
- <br />
63
- <v-btn
64
- class="mt-2 fullWidth"
65
- color="primary"
66
- outlined
67
- @click="onRemoveElement(itemIndex)"
68
- ><v-icon>mdi-delete-outline</v-icon
69
- >{{ $t('shared.forms.delete') }}</v-btn
70
- >
71
- </v-expansion-panel-content>
72
- </v-expansion-panel>
73
- </v-expansion-panels>
74
- </v-container>
44
+ <v-icon
45
+ v-if="
46
+ !block.metadata.config.items[index]
47
+ .expand
48
+ "
49
+ >mdi-arrow-expand-all</v-icon
50
+ >
51
+ <v-icon
52
+ v-if="
53
+ block.metadata.config.items[index]
54
+ .expand
55
+ "
56
+ >
57
+ mdi-arrow-collapse-all
58
+ </v-icon>
59
+ </v-btn>
60
+ <TextEditor
61
+ v-show="
62
+ !block.metadata.config.items[index].expand
63
+ "
64
+ v-model="
65
+ block.metadata.config.items[index].content
66
+ "
67
+ ></TextEditor>
68
+ </v-container>
69
+ </template>
70
+ </SortableExpansionPanel>
71
+ </v-container>
72
+ <v-container class="pa-0">
73
+ <v-row justify="center" class="my-4">
74
+ <v-btn color="primary" @click="onAddElement"
75
+ ><v-icon>mdi-plus</v-icon
76
+ >{{
77
+ $t(
78
+ 'windward.core.components.settings.accordion.add'
79
+ )
80
+ }}</v-btn
81
+ >
82
+ </v-row>
83
+ </v-container>
84
+ </v-form>
85
+ <div v-if="loading" class="text-center">
86
+ <v-progress-circular
87
+ :size="70"
88
+ :width="7"
89
+ color="primary"
90
+ indeterminate
91
+ ></v-progress-circular>
92
+ </div>
75
93
  </div>
76
94
  </template>
77
95
  <script>
@@ -79,11 +97,13 @@ import _ from 'lodash'
79
97
  import Crypto from '~/helpers/Crypto'
80
98
  import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
81
99
  import TextEditor from '~/components/Text/TextEditor'
100
+ import SortableExpansionPanel from '~/components/SortableExpansionPanel.vue'
82
101
 
83
102
  export default {
84
103
  name: 'AccordionSettings',
85
104
  components: {
86
105
  TextEditor,
106
+ SortableExpansionPanel,
87
107
  },
88
108
  extends: BaseContentSettings,
89
109
  beforeMount() {
@@ -108,15 +128,17 @@ export default {
108
128
  this.block.metadata.config.items = []
109
129
  this.block.metadata.config.items.push(defaultObject)
110
130
  }
111
- this.block.body = 'accordion'
131
+ this.block.body = this.$t(
132
+ 'windward.core.components.settings.accordion.accordion'
133
+ )
112
134
  },
113
135
  data() {
114
136
  return {
115
- api_key: process.env.TINY_MCE_API_KEY,
116
137
  expansionPanelKey: '0',
138
+ valid: true,
139
+ loading: false,
117
140
  }
118
141
  },
119
- mounted() {},
120
142
  beforeDestroy() {
121
143
  if (this.debouncer) {
122
144
  clearTimeout(this.debouncer)
@@ -140,6 +162,10 @@ export default {
140
162
  this.expansionPanelKey = Crypto.id()
141
163
  return (item.expand = !item.expand)
142
164
  },
165
+ onDragged() {
166
+ // need to remount body after dragged to update the content body on the element
167
+ this.expansionPanelKey = Crypto.id()
168
+ },
143
169
  },
144
170
  }
145
171
  </script>
@@ -147,7 +173,4 @@ export default {
147
173
  .v-progress-circular {
148
174
  margin: 1rem;
149
175
  }
150
- .fullWidth {
151
- width: 100%;
152
- }
153
176
  </style>