@windward/core 0.0.6 → 0.0.7

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 (36) hide show
  1. package/components/Content/Blocks/Image.vue +1 -6
  2. package/components/Content/Blocks/OpenResponse.vue +137 -0
  3. package/components/Content/Blocks/OpenResponseCollate.vue +158 -0
  4. package/components/Settings/OpenResponseCollateSettings.vue +170 -0
  5. package/components/Settings/OpenResponseSettings.vue +81 -0
  6. package/components/utils/TinyMCEWrapper.vue +13 -3
  7. package/i18n/en-US/components/content/blocks/index.ts +4 -0
  8. package/i18n/en-US/components/content/blocks/open_response.ts +5 -0
  9. package/i18n/en-US/components/content/blocks/open_response_collate.ts +6 -0
  10. package/i18n/en-US/components/settings/index.ts +5 -1
  11. package/i18n/en-US/components/settings/open_response.ts +5 -0
  12. package/i18n/en-US/components/settings/open_response_collate.ts +6 -0
  13. package/i18n/en-US/shared/content_blocks.ts +2 -0
  14. package/i18n/en-US/shared/settings.ts +3 -1
  15. package/i18n/es-ES/components/content/blocks/index.ts +4 -0
  16. package/i18n/es-ES/components/content/blocks/open_response.ts +6 -0
  17. package/i18n/es-ES/components/content/blocks/open_response_collate.ts +6 -0
  18. package/i18n/es-ES/components/settings/index.ts +4 -0
  19. package/i18n/es-ES/components/settings/open_response.ts +5 -0
  20. package/i18n/es-ES/components/settings/open_response_collate.ts +7 -0
  21. package/i18n/es-ES/shared/content_blocks.ts +2 -0
  22. package/i18n/es-ES/shared/settings.ts +3 -0
  23. package/i18n/sv-SE/components/content/blocks/index.ts +4 -0
  24. package/i18n/sv-SE/components/content/blocks/open_response.ts +6 -0
  25. package/i18n/sv-SE/components/content/blocks/open_response_collate.ts +6 -0
  26. package/i18n/sv-SE/components/settings/index.ts +5 -1
  27. package/i18n/sv-SE/components/settings/open_response.ts +5 -0
  28. package/i18n/sv-SE/components/settings/open_response_collate.ts +6 -0
  29. package/i18n/sv-SE/shared/content_blocks.ts +2 -0
  30. package/i18n/sv-SE/shared/settings.ts +2 -0
  31. package/package.json +1 -1
  32. package/plugin.js +43 -0
  33. package/test/Components/Content/Blocks/OpenResponse.spec.js +31 -0
  34. package/test/Components/Content/Blocks/OpenResponseCollate.spec.js +36 -0
  35. package/test/Components/Settings/OpenResponseCollateSettings.spec.js +20 -0
  36. package/test/Components/Settings/OpenResponseSettings.spec.js +20 -0
@@ -48,10 +48,10 @@ export default {
48
48
  },
49
49
  data() {
50
50
  return {
51
+ id: 'image_' + Crypto.id(),
51
52
  aspectRatio: undefined,
52
53
  }
53
54
  },
54
- extends: BaseContentBlock,
55
55
  beforeMount() {
56
56
  if (_.isEmpty(this.block.metadata.config)) {
57
57
  this.block.metadata.config = {}
@@ -63,11 +63,6 @@ export default {
63
63
  this.block.metadata.config.aria_describedby = ''
64
64
  }
65
65
  },
66
- data() {
67
- return {
68
- id: 'image_' + Crypto.id(),
69
- }
70
- },
71
66
  computed: {
72
67
  describedById() {
73
68
  // If there's a described by
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="stateLoaded">
4
+ <div v-if="block.body && !submitted">
5
+ <TextViewer v-model="block.body" :height="200"></TextViewer>
6
+ <TextEditor
7
+ v-model="response"
8
+ :height="200"
9
+ menubar=""
10
+ ></TextEditor>
11
+ <p class="pa-3 text-center blue-grey lighten-5">
12
+ <v-btn
13
+ color="primary"
14
+ :disabled="!canSubmit"
15
+ @click="onSubmit"
16
+ >
17
+ {{ $t('shared.forms.submit') }}
18
+ </v-btn>
19
+ </p>
20
+ </div>
21
+
22
+ <div v-else-if="block.body && submitted">
23
+ <TextViewer v-model="block.body" :height="200"></TextViewer>
24
+ <p>
25
+ {{
26
+ $t(
27
+ 'windward.core.components.content.blocks.open_response.your_response'
28
+ )
29
+ }}
30
+ </p>
31
+ <v-alert color="light-blue lighten-4">
32
+ <TextViewer v-model="response" :height="200"></TextViewer>
33
+ </v-alert>
34
+ <div v-if="block.metadata.config.sample_response">
35
+ <p>
36
+ {{
37
+ $t(
38
+ 'windward.core.components.content.blocks.open_response.sample_response'
39
+ )
40
+ }}
41
+ </p>
42
+ <v-alert color="light-blue lighten-4">
43
+ <TextViewer
44
+ v-model="block.metadata.config.sample_response"
45
+ :height="200"
46
+ ></TextViewer>
47
+ </v-alert>
48
+ </div>
49
+ <p class="pa-3 text-center blue-grey lighten-5">
50
+ <v-btn color="primary" @click="submitted = false">{{
51
+ $t('shared.forms.edit')
52
+ }}</v-btn>
53
+ </p>
54
+ </div>
55
+
56
+ <v-alert v-else type="warning">
57
+ {{
58
+ $t(
59
+ 'windward.core.components.content.blocks.open_response.initial_setup'
60
+ )
61
+ }}
62
+ </v-alert>
63
+ </div>
64
+ <div v-if="!stateLoaded">
65
+ <v-progress-circular
66
+ indeterminate
67
+ :size="64"
68
+ :width="4"
69
+ color="white"
70
+ >
71
+ </v-progress-circular>
72
+ </div>
73
+ </div>
74
+ </template>
75
+
76
+ <script>
77
+ import _ from 'lodash'
78
+ import TextViewer from '~/components/Text/TextViewer.vue'
79
+ import TextEditor from '~/components/Text/TextEditor.vue'
80
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
81
+
82
+ export default {
83
+ name: 'ContentBlockOpenResponse',
84
+ extends: BaseContentBlock,
85
+ components: {
86
+ TextViewer,
87
+ TextEditor,
88
+ },
89
+ data() {
90
+ return {
91
+ stateLoaded: false,
92
+ response: '',
93
+ submitted: false,
94
+ }
95
+ },
96
+ beforeMount() {
97
+ if (_.isEmpty(this.block.body)) {
98
+ this.block.body = ''
99
+ }
100
+ if (_.isEmpty(this.block.metadata.config)) {
101
+ this.block.metadata.config = {}
102
+ }
103
+ if (_.isEmpty(this.block.metadata.config.sample_response)) {
104
+ this.block.metadata.config.sample_response = ''
105
+ }
106
+ if (_.isEmpty(this.block.metadata.config.starting_text)) {
107
+ this.block.metadata.config.starting_text = ''
108
+ }
109
+ },
110
+ computed: {
111
+ canSubmit() {
112
+ // Make sure the response is not empty and not equal to the starting text
113
+ return (
114
+ this.response &&
115
+ this.response !== this.block.metadata.config.starting_text
116
+ )
117
+ },
118
+ },
119
+ watch: {},
120
+ mounted() {},
121
+ methods: {
122
+ onAfterSetContentBlockState() {
123
+ // If after the state is applied the response is still empty then apply the default response
124
+ if (this.response === '') {
125
+ this.response = this.block.metadata.config.starting_text
126
+ }
127
+ this.stateLoaded = true
128
+ },
129
+ onSubmit() {
130
+ this.submitted = true
131
+
132
+ // Force the state to save on submit and not wait
133
+ this.$Tracking.flushState()
134
+ },
135
+ },
136
+ }
137
+ </script>
@@ -0,0 +1,158 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="block.metadata.config.linked.length">
4
+ <v-btn color="primary" block @click="onCollate">
5
+ <v-icon class="mr-3">mdi-file-word</v-icon>
6
+ {{
7
+ $t(
8
+ 'windward.core.components.content.blocks.open_response_collate.download_document'
9
+ )
10
+ }}
11
+ </v-btn>
12
+ </div>
13
+ <v-alert v-else type="warning">
14
+ {{
15
+ $t(
16
+ 'windward.core.components.content.blocks.open_response_collate.initial_setup'
17
+ )
18
+ }}
19
+ </v-alert>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ import _ from 'lodash'
25
+ import { mapGetters } from 'vuex'
26
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
27
+ import UserContentBlockState from '~/models/UserContentBlockState'
28
+
29
+ export default {
30
+ name: 'ContentBlockOpenResponseCollate',
31
+ extends: BaseContentBlock,
32
+ components: {},
33
+ data() {
34
+ return {}
35
+ },
36
+ beforeMount() {
37
+ if (_.isEmpty(this.block.body)) {
38
+ this.block.body = ''
39
+ }
40
+ if (_.isEmpty(this.block.metadata.config)) {
41
+ this.block.metadata.config = {}
42
+ }
43
+ if (_.isEmpty(this.block.metadata.config.linked)) {
44
+ this.block.metadata.config.linked = []
45
+ }
46
+ if (_.isEmpty(this.block.metadata.config.filename)) {
47
+ this.block.metadata.config.filename = ''
48
+ }
49
+ if (_.isEmpty(this.block.metadata.config.include_prompts)) {
50
+ this.block.metadata.config.include_prompts = false
51
+ }
52
+ },
53
+ computed: {
54
+ ...mapGetters({
55
+ organization: 'organization/get',
56
+ course: 'course/get',
57
+ enrollment: 'enrollment/get',
58
+ content: 'content/get',
59
+ }),
60
+ },
61
+ watch: {},
62
+ mounted() {},
63
+ methods: {
64
+ async onCollate() {
65
+ let userState = await UserContentBlockState.where({
66
+ 'metadata->block->tag': 'plugin-core-open-response',
67
+ course_user_id: this.enrollment.id,
68
+ })
69
+ .whereIn('content_block_id', this.block.metadata.config.linked)
70
+ .get()
71
+ let collated = ''
72
+
73
+ userState.forEach((state) => {
74
+ // Prepend the prompt from the state if include prompts is enabled
75
+ if (this.block.metadata.config.include_prompts) {
76
+ collated +=
77
+ '<strong>' +
78
+ state.metadata.block.body +
79
+ '</strong><hr />'
80
+ }
81
+ if (!_.isEmpty(state.metadata.response)) {
82
+ collated += '\n' + state.metadata.response
83
+ } else {
84
+ collated +=
85
+ '\n<p>' +
86
+ this.$t(
87
+ 'windward.core.components.content.blocks.open_response_collate.no_response'
88
+ ) +
89
+ '</p>'
90
+ }
91
+ })
92
+ let filename = this.block.metadata.config.filename
93
+ if (_.isEmpty(this.block.metadata.config.filename)) {
94
+ // Default filename is the users name + the current page
95
+ filename =
96
+ this.$auth.user.last_name +
97
+ '_' +
98
+ this.$auth.user.first_name +
99
+ '_' +
100
+ _.get(this.content, 'content.name_prefix') +
101
+ _.get(this.content, 'content.name')
102
+
103
+ // Change spaces to underscores and remove special characters
104
+ filename = filename.replaceAll(/\s+/gi, '_')
105
+ filename = filename.replaceAll(/[^a-z0-9\-\_]/gi, '')
106
+ }
107
+
108
+ this.generateDocument(collated, filename)
109
+ },
110
+ generateDocument(htmlBody, filename = '') {
111
+ // Specify file name. If one isn't supplied then a default name of `exported_document_YYYY-MM-DD.doc` is used
112
+ filename = filename
113
+ ? filename + '.doc'
114
+ : 'exported_document_' +
115
+ new Date().toISOString().split('T')[0] +
116
+ '.doc'
117
+
118
+ var preHtml =
119
+ "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'>" +
120
+ "<head><meta charset='utf-8'><title>" +
121
+ filename +
122
+ '</title></head>' +
123
+ '<body>'
124
+ var postHtml = '</body></html>'
125
+ var html = preHtml + htmlBody + postHtml
126
+
127
+ var blob = new Blob(['\ufeff', html], {
128
+ type: 'application/msword',
129
+ })
130
+
131
+ // Specify link url
132
+ var url =
133
+ 'data:application/vnd.ms-word;charset=utf-8,' +
134
+ encodeURIComponent(html)
135
+
136
+ // Create download link element
137
+ var downloadLink = document.createElement('a')
138
+
139
+ document.body.appendChild(downloadLink)
140
+
141
+ if (navigator.msSaveOrOpenBlob) {
142
+ navigator.msSaveOrOpenBlob(blob, filename)
143
+ } else {
144
+ // Create a link to the file
145
+ downloadLink.href = url
146
+
147
+ // Setting the file name
148
+ downloadLink.download = filename
149
+
150
+ //triggering the function
151
+ downloadLink.click()
152
+ }
153
+
154
+ document.body.removeChild(downloadLink)
155
+ },
156
+ },
157
+ }
158
+ </script>
@@ -0,0 +1,170 @@
1
+ <template>
2
+ <v-container>
3
+ <v-form>
4
+ <p>
5
+ {{
6
+ $t(
7
+ 'windward.core.components.settings.open_response_collate.instructions'
8
+ )
9
+ }}
10
+ </p>
11
+ <v-switch
12
+ v-model="block.metadata.config.include_prompts"
13
+ :label="
14
+ $t(
15
+ 'windward.core.components.settings.open_response_collate.include_prompts'
16
+ )
17
+ "
18
+ ></v-switch>
19
+ <v-text-field
20
+ v-model="block.metadata.config.filename"
21
+ :label="
22
+ $t(
23
+ 'windward.core.components.settings.open_response_collate.filename'
24
+ )
25
+ "
26
+ ></v-text-field>
27
+ <v-list>
28
+ <v-list-item-group
29
+ v-model="linked"
30
+ multiple
31
+ color="primary"
32
+ @change="onLinkedChange"
33
+ >
34
+ <draggable
35
+ v-bind="dragOptions"
36
+ :list="contentBlocks"
37
+ @change="onDragChange"
38
+ >
39
+ <v-list-item
40
+ v-for="contentBlock in contentBlocks"
41
+ :key="contentBlock.id"
42
+ :value="contentBlock.id"
43
+ >
44
+ <template #default="{ active }">
45
+ <v-list-item-icon>
46
+ <v-icon>mdi-drag</v-icon>
47
+ </v-list-item-icon>
48
+
49
+ <v-list-item-content>
50
+ <v-list-item-title>
51
+ {{
52
+ contentBlock.block.body.replace(
53
+ /<[^>]*>?/gm,
54
+ ''
55
+ )
56
+ }}
57
+ </v-list-item-title>
58
+ </v-list-item-content>
59
+ <v-list-item-action>
60
+ <v-checkbox
61
+ :input-value="active"
62
+ color="primary"
63
+ ></v-checkbox>
64
+ </v-list-item-action>
65
+ </template>
66
+ </v-list-item>
67
+ </draggable>
68
+ </v-list-item-group>
69
+ </v-list>
70
+ </v-form>
71
+ </v-container>
72
+ </template>
73
+
74
+ <script>
75
+ import _ from 'lodash'
76
+ import { mapGetters } from 'vuex'
77
+ import draggable from 'vuedraggable'
78
+ import TextEditor from '~/components/Text/TextEditor.vue'
79
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
80
+ import ContentBlock from '~/models/ContentBlock'
81
+ import Course from '~/models/Course'
82
+
83
+ export default {
84
+ name: 'ImageSettings',
85
+ extends: BaseContentSettings,
86
+ components: { draggable, TextEditor },
87
+ props: {
88
+ settings: { type: Object, required: false, default: null },
89
+ context: { type: String, required: false, default: 'block' },
90
+ },
91
+ data() {
92
+ return {
93
+ contentBlocks: [],
94
+ linked: [],
95
+ }
96
+ },
97
+ computed: {
98
+ ...mapGetters({
99
+ organization: 'organization/get',
100
+ course: 'course/get',
101
+ enrollment: 'enrollment/get',
102
+ }),
103
+ dragOptions() {
104
+ return {
105
+ animation: 200,
106
+ }
107
+ },
108
+ },
109
+ async fetch() {
110
+ this.contentBlocks = await ContentBlock.where(
111
+ 'tag',
112
+ 'plugin-core-open-response'
113
+ )
114
+ .for(new Course({ id: this.course.id }))
115
+ .get()
116
+ },
117
+ beforeMount() {
118
+ if (_.isEmpty(this.block)) {
119
+ this.block = {}
120
+ }
121
+ if (_.isEmpty(this.block.body)) {
122
+ this.block.body = ''
123
+ }
124
+ if (_.isEmpty(this.block.metadata)) {
125
+ this.block.metadata = {}
126
+ }
127
+ if (_.isEmpty(this.block.metadata.config)) {
128
+ this.block.metadata.config = {}
129
+ }
130
+ if (_.isEmpty(this.block.metadata.config.linked)) {
131
+ this.block.metadata.config.linked = []
132
+ }
133
+ if (_.isEmpty(this.block.metadata.config.filename)) {
134
+ this.block.metadata.config.filename = ''
135
+ }
136
+ if (_.isEmpty(this.block.metadata.config.include_prompts)) {
137
+ this.block.metadata.config.include_prompts = false
138
+ }
139
+
140
+ this.linked = this.block.metadata.config.linked
141
+ },
142
+ watch: {},
143
+ mounted() {},
144
+ methods: {
145
+ // Called when the order changes
146
+ onDragChange(e) {
147
+ this.setLinkedBlocks()
148
+ },
149
+ // Called when blocks are added / removed
150
+ onLinkedChange() {
151
+ this.setLinkedBlocks()
152
+ },
153
+ setLinkedBlocks() {
154
+ const linkedContentIds = []
155
+
156
+ // Loop over content blocks since they have the correct order we want to collate
157
+ this.contentBlocks.forEach((contentBlock) => {
158
+ // If the unsorted this.linked includes the block id, add it in the right order
159
+ if (this.linked.includes(contentBlock.id)) {
160
+ linkedContentIds.push(contentBlock.id)
161
+ }
162
+ })
163
+
164
+ // Set the linked and also body for convenience
165
+ this.block.metadata.config.linked = linkedContentIds
166
+ this.block.body = linkedContentIds.join()
167
+ },
168
+ },
169
+ }
170
+ </script>
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <v-container>
3
+ <v-form>
4
+ <h3 class="pb-2">
5
+ {{
6
+ $t(
7
+ 'windward.core.components.settings.open_response.question'
8
+ )
9
+ }}
10
+ </h3>
11
+ <TextEditor v-model="block.body" :height="200"></TextEditor>
12
+
13
+ <h3 class="pb-2">
14
+ {{
15
+ $t(
16
+ 'windward.core.components.settings.open_response.sample_response'
17
+ )
18
+ }}
19
+ </h3>
20
+ <TextEditor
21
+ v-model="block.metadata.config.sample_response"
22
+ :height="200"
23
+ ></TextEditor>
24
+
25
+ <h3 class="pb-2">
26
+ {{
27
+ $t(
28
+ 'windward.core.components.settings.open_response.starting_text'
29
+ )
30
+ }}
31
+ </h3>
32
+ <TextEditor
33
+ v-model="block.metadata.config.starting_text"
34
+ :height="200"
35
+ ></TextEditor>
36
+ </v-form>
37
+ </v-container>
38
+ </template>
39
+
40
+ <script>
41
+ import _ from 'lodash'
42
+ import TextEditor from '~/components/Text/TextEditor.vue'
43
+ import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
44
+ import ContentBlockAsset from '~/components/Content/ContentBlockAsset.vue'
45
+
46
+ export default {
47
+ name: 'ImageSettings',
48
+ extends: BaseContentSettings,
49
+ components: { ContentBlockAsset, TextEditor },
50
+ props: {
51
+ settings: { type: Object, required: false, default: null },
52
+ context: { type: String, required: false, default: 'block' },
53
+ },
54
+ beforeMount() {
55
+ if (_.isEmpty(this.block)) {
56
+ this.block = {}
57
+ }
58
+ if (_.isEmpty(this.block.body)) {
59
+ this.block.body = ''
60
+ }
61
+ if (_.isEmpty(this.block.metadata)) {
62
+ this.block.metadata = {}
63
+ }
64
+ if (_.isEmpty(this.block.metadata.config)) {
65
+ this.block.metadata.config = {}
66
+ }
67
+ if (_.isEmpty(this.block.metadata.config.sample_response)) {
68
+ this.block.metadata.config.sample_response = ''
69
+ }
70
+ if (_.isEmpty(this.block.metadata.config.starting_text)) {
71
+ this.block.metadata.config.starting_text = ''
72
+ }
73
+ },
74
+ data() {
75
+ return {}
76
+ },
77
+ watch: {},
78
+ mounted() {},
79
+ methods: {},
80
+ }
81
+ </script>
@@ -26,6 +26,17 @@ export default {
26
26
  value: { type: String, required: true, default: '' },
27
27
  api_key: { type: String, required: true, default: '' },
28
28
  height: { type: Number, required: false, default: null },
29
+ menubar: {
30
+ type: String,
31
+ required: false,
32
+ default: 'file edit insert format view table windward help',
33
+ },
34
+ toolbar: {
35
+ type: String,
36
+ required: false,
37
+ default:
38
+ 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | table bullist numlist outdent indent | mathButton ',
39
+ },
29
40
  },
30
41
  beforeMount() {
31
42
  this.text = this.value
@@ -50,7 +61,7 @@ export default {
50
61
  return {
51
62
  height: 500,
52
63
  visual: false,
53
- menubar: 'file edit insert format view table windward help',
64
+ menubar: this.menubar,
54
65
  menu: {
55
66
  insert: {
56
67
  title: 'Insert',
@@ -67,8 +78,7 @@ export default {
67
78
  'anchor insertdatetime ',
68
79
  'paste code wordcount table WindwardToolKit ',
69
80
  ],
70
- toolbar:
71
- 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | table bullist numlist outdent indent | mathButton ',
81
+ toolbar: this.toolbar,
72
82
  table_advtab: false,
73
83
  table_cell_advtab: false,
74
84
  table_row_advtab: false,
@@ -4,6 +4,8 @@ import video from './video'
4
4
  import table from './table'
5
5
  import tab from './tab'
6
6
  import feedback from './feedback'
7
+ import open_response from './open_response'
8
+ import open_response_collate from './open_response_collate'
7
9
 
8
10
  export default {
9
11
  user_upload,
@@ -12,4 +14,6 @@ export default {
12
14
  table,
13
15
  tab,
14
16
  feedback,
17
+ open_response,
18
+ open_response_collate,
15
19
  }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ initial_setup: 'Enter a prompt for this open response block to get started',
3
+ your_response: 'Your Response',
4
+ sample_response: 'Suggested/Sample Response',
5
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ download_document: 'Download Word Document',
3
+ no_response: '[no response]',
4
+ initial_setup:
5
+ 'Open the block settings and select Open Response blocks you want to collate for download',
6
+ }
@@ -3,11 +3,15 @@ import user_upload from './user_upload'
3
3
  import text_editor from './text_editor'
4
4
  import video from './video'
5
5
  import clickable_icon from './clickable_icon'
6
+ import open_response from './open_response'
7
+ import open_response_collate from './open_response_collate'
6
8
 
7
9
  export default {
8
10
  image,
9
11
  user_upload,
10
12
  text_editor,
11
13
  video,
12
- clickable_icon
14
+ clickable_icon,
15
+ open_response,
16
+ open_response_collate,
13
17
  }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ question: 'Question',
3
+ sample_response: 'Suggested/Sample Response',
4
+ starting_text: 'Starting Text',
5
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ instructions:
3
+ 'Check off open responses to collate. Drag the prompts to set the order you want the responses collated',
4
+ include_prompts: 'Include Prompts',
5
+ filename: 'Filename (Blank for current page name)',
6
+ }
@@ -7,6 +7,8 @@ export default {
7
7
  rich_text: 'Rich Text',
8
8
  math: 'Math',
9
9
  accordion: 'Accordion',
10
+ open_response: 'Open Response',
11
+ open_response_collate: 'Open Response Collate',
10
12
  image: 'Image',
11
13
  user_upload: 'User Upload',
12
14
  clickable_icons: 'Clickable Icons',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  title: {
3
3
  assessment: 'Assessment Settings',
4
+ open_response: 'Open Response Settings',
5
+ open_response_collate: 'Open Response Collate Settings',
4
6
  image: 'Image Settings',
5
7
  user_upload: 'User Upload Settings',
6
8
  tab_settings: 'Tab Settings',
@@ -10,6 +12,6 @@ export default {
10
12
  video: 'Video Settings',
11
13
  table: 'Table Settings',
12
14
  math: 'Math Settings',
13
- feedback: 'Feedback Settings'
15
+ feedback: 'Feedback Settings',
14
16
  },
15
17
  }
@@ -4,6 +4,8 @@ import video from './video'
4
4
  import table from './table'
5
5
  import tab from './tab'
6
6
  import feedback from './feedback'
7
+ import open_response from './open_response'
8
+ import open_response_collate from './open_response_collate'
7
9
 
8
10
  export default {
9
11
  user_upload,
@@ -12,4 +14,6 @@ export default {
12
14
  table,
13
15
  tab,
14
16
  feedback,
17
+ open_response,
18
+ open_response_collate,
15
19
  }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ initial_setup:
3
+ 'Ingrese un mensaje para este bloque de respuesta abierto para comenzar',
4
+ your_response: 'Tu respuesta',
5
+ sample_response: 'Respuesta sugerida/de muestra',
6
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ download_document: 'Descargar documento de Word',
3
+ no_response: '[sin respuesta]',
4
+ initial_setup:
5
+ 'Abra la configuración del bloque y seleccione los bloques de respuesta abierta que desea recopilar para descargar',
6
+ }
@@ -3,6 +3,8 @@ import user_upload from './user_upload'
3
3
  import text_editor from './text_editor'
4
4
  import video from './video'
5
5
  import clickable_icon from './clickable_icon'
6
+ import open_response from './open_response'
7
+ import open_response_collate from './open_response_collate'
6
8
 
7
9
  export default {
8
10
  image,
@@ -10,4 +12,6 @@ export default {
10
12
  text_editor,
11
13
  video,
12
14
  clickable_icon,
15
+ open_response,
16
+ open_response_collate,
13
17
  }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ question: 'Pregunta',
3
+ sample_response: 'Respuesta sugerida/de muestra',
4
+ starting_text: 'Texto inicial',
5
+ }
@@ -0,0 +1,7 @@
1
+ export default {
2
+ instructions:
3
+ 'Marque las respuestas abiertas para cotejar. Arrastra las indicaciones para establecer el orden en el que deseas que se cotejen las respuestas',
4
+ include_prompts: 'Incluir mensajes',
5
+ filename:
6
+ 'Nombre de archivo (en blanco para el nombre de la página actual)',
7
+ }
@@ -7,6 +7,8 @@ export default {
7
7
  rich_text: 'Texto enriquecido',
8
8
  math: 'Matemáticas',
9
9
  accordion: 'Acordeón',
10
+ open_response: 'Respuesta abierta',
11
+ open_response_collate: 'Intercalación de respuesta abierta',
10
12
  image: 'Imagen',
11
13
  user_upload: 'Carga de usuario',
12
14
  clickable_icons: 'Iconos en los que se puede hacer clic',
@@ -1,6 +1,9 @@
1
1
  export default {
2
2
  title: {
3
3
  assessment: 'Configuración de evaluación',
4
+ open_response: 'Abrir configuración de respuesta',
5
+ open_response_collate:
6
+ 'Abrir configuración de clasificación de respuestas',
4
7
  image: 'Configuración de imagen',
5
8
  user_upload: 'Configuración de carga del usuario',
6
9
  tab_settings: 'Configuración de pestaña',
@@ -4,6 +4,8 @@ import video from './video'
4
4
  import table from './table'
5
5
  import tab from './tab'
6
6
  import feedback from './feedback'
7
+ import open_response from './open_response'
8
+ import open_response_collate from './open_response_collate'
7
9
 
8
10
  export default {
9
11
  user_upload,
@@ -12,4 +14,6 @@ export default {
12
14
  table,
13
15
  tab,
14
16
  feedback,
17
+ open_response,
18
+ open_response_collate,
15
19
  }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ initial_setup:
3
+ 'Ange en uppmaning för detta öppna svarsblock för att komma igång',
4
+ your_response: 'Ditt svar',
5
+ sample_response: 'Föreslagen/provsvar',
6
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ download_document: 'Ladda ner Word-dokument',
3
+ no_response: '[inget svar]',
4
+ initial_setup:
5
+ 'Öppna blockinställningarna och välj Öppna svarsblock som du vill sortera för nedladdning',
6
+ }
@@ -3,11 +3,15 @@ import user_upload from './user_upload'
3
3
  import text_editor from './text_editor'
4
4
  import video from './video'
5
5
  import clickable_icon from './clickable_icon'
6
+ import open_response from './open_response'
7
+ import open_response_collate from './open_response_collate'
6
8
 
7
9
  export default {
8
10
  image,
9
11
  user_upload,
10
12
  text_editor,
11
13
  video,
12
- clickable_icon
14
+ clickable_icon,
15
+ open_response,
16
+ open_response_collate,
13
17
  }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ question: 'Fråga',
3
+ sample_response: 'Föreslagen/provsvar',
4
+ starting_text: 'Starttext',
5
+ }
@@ -0,0 +1,6 @@
1
+ export default {
2
+ instructions:
3
+ 'Bocka av öppna svar för att sortera. Dra uppmaningarna för att ställa in den ordning du vill att svaren ska sorteras',
4
+ include_prompts: 'Inkludera uppmaningar',
5
+ filename: 'Filnamn (tomt för nuvarande sidnamn)',
6
+ }
@@ -7,6 +7,8 @@ export default {
7
7
  rich_text: 'Rich Text',
8
8
  math: 'Math',
9
9
  accordion: 'Accordion',
10
+ open_response: 'Öppet svar',
11
+ open_response_collate: 'Öppna svarssortering',
10
12
  image: 'Bild',
11
13
  user_upload: 'User Upload',
12
14
  clickable_icons: 'Klickbara ikoner',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  title: {
3
3
  assessment: 'Bedömningsinställningar',
4
+ open_response: 'Öppna svarsinställningar',
5
+ open_response_collate: 'Öppna inställningar för svarssortering',
4
6
  image: 'Bildinställningar',
5
7
  user_upload: 'User Upload Settings',
6
8
  tab_settings: 'Flikinställningar',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/core",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Windward UI Core Plugins",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
package/plugin.js CHANGED
@@ -11,6 +11,8 @@ import ClickableIcons from './components/Content/Blocks/ClickableIcons'
11
11
 
12
12
  import UserUploadNav from './components/Navigation/Items/UserUploadNav.vue'
13
13
 
14
+ import OpenResponse from './components/Content/Blocks/OpenResponse'
15
+ import OpenResponseCollate from './components/Content/Blocks/OpenResponseCollate'
14
16
  import Image from './components/Content/Blocks/Image'
15
17
  import UserUpload from './components/Content/Blocks/UserUpload'
16
18
 
@@ -18,7 +20,10 @@ import GlossaryPage from './pages/glossary.vue'
18
20
  import CourseGlossaryToolNav from './components/Navigation/Items/CourseGlossaryToolNav.vue'
19
21
  import GlossaryNav from './components/Navigation/Items/GlossaryNav.vue'
20
22
  import AskTheExpert from './components/Navigation/Items/AskTheExpert.vue'
23
+
21
24
  // Entrypoint for npm
25
+ import OpenResponseSettings from './components/Settings/OpenResponseSettings.vue'
26
+ import OpenResponseCollateSettings from './components/Settings/OpenResponseCollateSettings.vue'
22
27
  import ImageSettings from './components/Settings/ImageSettings.vue'
23
28
  import UserUploadSettings from './components/Settings/UserUploadSettings.vue'
24
29
  import ClickableIconsSettings from './components/Settings/ClickableIconsSettings.vue'
@@ -176,6 +181,26 @@ export default {
176
181
  'windward.core.shared.content_blocks.grouping.basic',
177
182
  },
178
183
  },
184
+ {
185
+ tag: 'core-open-response',
186
+ template: OpenResponse,
187
+ metadata: {
188
+ icon: 'mdi-typewriter',
189
+ name: 'windward.core.shared.content_blocks.title.open_response',
190
+ grouping:
191
+ 'windward.core.shared.content_blocks.grouping.basic',
192
+ },
193
+ },
194
+ {
195
+ tag: 'core-open-response-collate',
196
+ template: OpenResponseCollate,
197
+ metadata: {
198
+ icon: 'mdi-typewriter',
199
+ name: 'windward.core.shared.content_blocks.title.open_response_collate',
200
+ grouping:
201
+ 'windward.core.shared.content_blocks.grouping.basic',
202
+ },
203
+ },
179
204
  {
180
205
  tag: 'core-image',
181
206
  template: Image,
@@ -218,6 +243,24 @@ export default {
218
243
  },
219
244
  ],
220
245
  settings: [
246
+ {
247
+ tag: 'core-open-response-settings',
248
+ template: OpenResponseSettings,
249
+ context: ['block.core-open-response'],
250
+ metadata: {
251
+ icon: 'mdi-cog',
252
+ name: 'windward.core.shared.settings.title.open_response',
253
+ },
254
+ },
255
+ {
256
+ tag: 'core-open-response-collate-settings',
257
+ template: OpenResponseCollateSettings,
258
+ context: ['block.core-open-response-collate'],
259
+ metadata: {
260
+ icon: 'mdi-cog',
261
+ name: 'windward.core.shared.settings.title.open_response_collate',
262
+ },
263
+ },
221
264
  {
222
265
  tag: 'core-image-settings',
223
266
  template: ImageSettings,
@@ -0,0 +1,31 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+ import Vue from 'vue'
3
+ import Vuetify from 'vuetify'
4
+ import { defaultMocks } from '@/test/mocks'
5
+ import OpenResponse from '@/components/Content/Blocks/OpenResponse.vue'
6
+
7
+ Vue.use(Vuetify)
8
+
9
+ describe('OpenResponse content block component', () => {
10
+ test('is a Vue instance', () => {
11
+ const wrapper = shallowMount(OpenResponse, {
12
+ vuetify: new Vuetify(),
13
+ mocks: defaultMocks,
14
+ propsData: {
15
+ value: {
16
+ id: '00000000-0000-0000-0000-000000000000',
17
+ tag: 'plugin-core-open-response',
18
+ body: '<p>Test Block</p>',
19
+ metadata: {
20
+ config: {
21
+ sample_response: 'sample response example',
22
+ starting_text: 'starting text example',
23
+ },
24
+ },
25
+ },
26
+ },
27
+ })
28
+
29
+ expect(wrapper.vm).toBeTruthy()
30
+ })
31
+ })
@@ -0,0 +1,36 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+ import Vue from 'vue'
3
+ import Vuetify from 'vuetify'
4
+ import { defaultMocks } from '@/test/mocks'
5
+ import Image from '@/components/Content/Blocks/Image.vue'
6
+
7
+ Vue.use(Vuetify)
8
+
9
+ describe('Image content block component', () => {
10
+ test('is a Vue instance', () => {
11
+ const wrapper = shallowMount(Image, {
12
+ vuetify: new Vuetify(),
13
+ mocks: defaultMocks,
14
+ propsData: {
15
+ value: {
16
+ id: '00000000-0000-0000-0000-000000000000',
17
+ tag: 'plugin-core-open-response-collate',
18
+ body: '00000000-0000-0000-0000-000000000001,00000000-0000-0000-0000-000000000002,00000000-0000-0000-0000-000000000003',
19
+ metadata: {
20
+ config: {
21
+ linked: [
22
+ '00000000-0000-0000-0000-000000000001',
23
+ '00000000-0000-0000-0000-000000000002',
24
+ '00000000-0000-0000-0000-000000000003',
25
+ ],
26
+ filename: 'example_filename_override',
27
+ include_prompts: true,
28
+ },
29
+ },
30
+ },
31
+ },
32
+ })
33
+
34
+ expect(wrapper.vm).toBeTruthy()
35
+ })
36
+ })
@@ -0,0 +1,20 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+ import Vuetify from 'vuetify'
3
+ import Vue from 'vue'
4
+
5
+ import { defaultMocks } from '@/test/mocks'
6
+ import OpenResponseCollateSettings from '@/components/Settings/OpenResponseCollateSettings'
7
+
8
+ Vue.use(Vuetify)
9
+
10
+ describe('OpenResponseCollateSettings', () => {
11
+ test('is a Vue instance', () => {
12
+ const wrapper = shallowMount(OpenResponseCollateSettings, {
13
+ propsData: {
14
+ tag: 'core-open-response-collate-settings',
15
+ },
16
+ mocks: defaultMocks,
17
+ })
18
+ expect(wrapper.vm).toBeTruthy()
19
+ })
20
+ })
@@ -0,0 +1,20 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+ import Vuetify from 'vuetify'
3
+ import Vue from 'vue'
4
+
5
+ import { defaultMocks } from '@/test/mocks'
6
+ import OpenResponseSettings from '@/components/Settings/OpenResponseSettings'
7
+
8
+ Vue.use(Vuetify)
9
+
10
+ describe('OpenResponseSettings', () => {
11
+ test('is a Vue instance', () => {
12
+ const wrapper = shallowMount(OpenResponseSettings, {
13
+ propsData: {
14
+ tag: 'core-open-response-settings',
15
+ },
16
+ mocks: defaultMocks,
17
+ })
18
+ expect(wrapper.vm).toBeTruthy()
19
+ })
20
+ })