@windward/core 0.4.3 → 0.5.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 (54) hide show
  1. package/components/Content/Blocks/Accordion.vue +10 -6
  2. package/components/Content/Blocks/BlockQuote.vue +81 -98
  3. package/components/Content/Blocks/ClickableIcons.vue +6 -5
  4. package/components/Content/Blocks/Feedback.vue +1 -1
  5. package/components/Content/Blocks/FileDownload/FileLinks.vue +82 -0
  6. package/components/Content/Blocks/FileDownload/FileTable.vue +106 -0
  7. package/components/Content/Blocks/FileDownload.vue +145 -0
  8. package/components/Content/Blocks/GenerateAIQuestionButton.vue +61 -0
  9. package/components/Content/Blocks/ScenarioChoice.vue +2 -2
  10. package/components/Content/Blocks/UserUpload.vue +15 -36
  11. package/components/Content/Blocks/Video.vue +7 -57
  12. package/components/Settings/AccordionSettings.vue +3 -6
  13. package/components/Settings/BlockQuoteSettings.vue +44 -14
  14. package/components/Settings/EmailSettings.vue +2 -2
  15. package/components/Settings/FileDownloadSettings.vue +168 -0
  16. package/components/Settings/UserUploadSettings.vue +36 -39
  17. package/components/Settings/VideoSettings.vue +15 -2
  18. package/components/utils/ContentViewer.vue +1 -0
  19. package/components/utils/TinyMCEWrapper.vue +14 -16
  20. package/components/utils/assets/tinymce/content/global.scss +10 -0
  21. package/i18n/en-US/components/content/blocks/file_download.ts +5 -0
  22. package/i18n/en-US/components/content/blocks/generate_questions.ts +3 -0
  23. package/i18n/en-US/components/content/blocks/index.ts +4 -0
  24. package/i18n/en-US/components/content/blocks/user_upload.ts +0 -2
  25. package/i18n/en-US/components/settings/block_quote.ts +6 -0
  26. package/i18n/en-US/components/settings/file_download.ts +8 -0
  27. package/i18n/en-US/components/settings/index.ts +2 -0
  28. package/i18n/en-US/shared/content_blocks.ts +1 -0
  29. package/i18n/en-US/shared/settings.ts +1 -3
  30. package/i18n/es-ES/components/content/blocks/file_download.ts +5 -0
  31. package/i18n/es-ES/components/content/blocks/generate_questions.ts +3 -0
  32. package/i18n/es-ES/components/content/blocks/index.ts +6 -2
  33. package/i18n/es-ES/components/content/blocks/user_upload.ts +0 -2
  34. package/i18n/es-ES/components/settings/block_quote.ts +7 -1
  35. package/i18n/es-ES/components/settings/file_download.ts +8 -0
  36. package/i18n/es-ES/components/settings/index.ts +4 -2
  37. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  38. package/i18n/es-ES/shared/settings.ts +1 -3
  39. package/i18n/sv-SE/components/content/blocks/file_download.ts +5 -0
  40. package/i18n/sv-SE/components/content/blocks/generate_questions.ts +3 -0
  41. package/i18n/sv-SE/components/content/blocks/index.ts +4 -0
  42. package/i18n/sv-SE/components/content/blocks/user_upload.ts +0 -2
  43. package/i18n/sv-SE/components/settings/block_quote.ts +7 -1
  44. package/i18n/sv-SE/components/settings/file_download.ts +8 -0
  45. package/i18n/sv-SE/components/settings/index.ts +4 -2
  46. package/i18n/sv-SE/shared/content_blocks.ts +1 -0
  47. package/i18n/sv-SE/shared/settings.ts +2 -4
  48. package/package.json +2 -2
  49. package/plugin.js +20 -0
  50. package/test/Components/Content/Blocks/FileDownload.spec.js +25 -0
  51. package/test/Components/Content/Blocks/Video.spec.js +0 -22
  52. package/test/Components/Settings/FileDownloadSettings.spec.js +20 -0
  53. package/test/Components/Settings/UserUploadSettings.spec.js +1 -1
  54. package/utils/index.js +2 -0
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div>
3
3
  <v-expansion-panels
4
- v-model="selectedPanels"
4
+ :value="selectedPanels"
5
5
  flat
6
6
  accordion
7
7
  focusable
@@ -101,9 +101,6 @@ export default {
101
101
  this.block.metadata.config.items = []
102
102
  this.block.metadata.config.items.push(defaultObject)
103
103
  }
104
- if (_.isEmpty(this.block.metadata.config.selectedPanels)) {
105
- this.block.metadata.config.selectedPanels = 0
106
- }
107
104
  this.block.body = this.$t(
108
105
  'windward.core.shared.content_blocks.title.accordion'
109
106
  )
@@ -112,7 +109,7 @@ export default {
112
109
  return {
113
110
  expansionPanelKey: '0',
114
111
  editingInContentItem: false,
115
- selectedPanels: 0,
112
+ selectedPanels: null,
116
113
  }
117
114
  },
118
115
  watch: {
@@ -125,6 +122,7 @@ export default {
125
122
  this.selectedPanels = newValue.metadata.config.selectedPanels
126
123
  this.expansionPanelKey = Crypto.id()
127
124
  }
125
+
128
126
  const length = newValue.metadata.config.items.length
129
127
  let counter = 0
130
128
  newValue.metadata.config.items.forEach((element) => {
@@ -148,10 +146,16 @@ export default {
148
146
  this.block.metadata.config.items.forEach((element) => {
149
147
  element.expand = false
150
148
  })
151
- this.selectedPanels = 0
149
+ this.selectedPanels = null
152
150
  }
153
151
  },
154
152
  },
153
+ mounted() {
154
+ if (this.render) {
155
+ // ensure panels are always loaded closed
156
+ this.selectedPanels = null
157
+ }
158
+ },
155
159
  methods: {
156
160
  getImagePublicUrl(asset) {
157
161
  const foundAsset = this.resolveAsset(asset)
@@ -21,17 +21,18 @@
21
21
  </v-col>
22
22
  <v-col cols="11" class="pl-0">
23
23
  <p class="pt-2">
24
- {{ block.metadata.config.block_quote.quote }}
24
+ <TextViewer
25
+ v-model="block.metadata.config.block_quote.quote"
26
+ ></TextViewer>
25
27
  </p>
26
28
  </v-col>
27
29
  </v-row>
28
30
  <v-row>
29
31
  <v-col cols="12">
30
- <p v-if="render">
31
- {{ finalcitation
32
- }}<span :class="classCitation">{{ finalsource }}</span>
32
+ <p>
33
+ {{ citation }}
34
+ <span :class="sourceClass">{{ source }}</span>
33
35
  </p>
34
- <p v-if="!render">Citation Here</p>
35
36
  </v-col>
36
37
  </v-row>
37
38
  </v-container>
@@ -39,6 +40,9 @@
39
40
 
40
41
  <script>
41
42
  import _ from 'lodash'
43
+ import he from 'he'
44
+
45
+ import TextViewer from '~/components/Text/TextViewer.vue'
42
46
  import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
43
47
 
44
48
  export default {
@@ -68,6 +72,7 @@ export default {
68
72
  organization: '',
69
73
  source_title: '',
70
74
  source_type: '',
75
+ source_url: '',
71
76
  }
72
77
  }
73
78
  this.block.body = this.$t(
@@ -75,108 +80,86 @@ export default {
75
80
  )
76
81
  },
77
82
  data() {
78
- return {
79
- finalcitation: '',
80
- finalsource: '',
81
- classCitation: '',
82
- }
83
+ return {}
83
84
  },
84
- watch: {
85
- render(newValue) {
86
- if (newValue) {
87
- this.createCitation()
85
+ computed: {
86
+ citation() {
87
+ const parts = []
88
+
89
+ // List of all keys in `block.metadata.config.block_quote.x` to include in the citation
90
+ const keys = ['author', 'author_title', 'organization']
91
+
92
+ // Go over all citation keys to compile
93
+ for (const key of keys) {
94
+ const value = this.block.metadata.config.block_quote[key] || ''
95
+
96
+ if (value) {
97
+ parts.push(value)
98
+ }
99
+ }
100
+
101
+ // If there were parts to return then prepend with a mdash
102
+ if (parts.length > 0) {
103
+ return he.decode('&mdash;') + parts.join(', ')
104
+ } else {
105
+ return ''
88
106
  }
89
107
  },
90
- },
91
- mounted() {
92
- this.createCitation()
93
- },
94
- methods: {
95
- createCitation() {
96
- this.finalcitation = ''
97
- this.finalsource = ''
98
- let counter = 0
99
- for (const property in this.block.metadata.config.block_quote) {
100
- // author details processed here counter added to see if a comma is needed before key
101
- if (
102
- property !== 'quote' &&
103
- property !== 'source_type' &&
104
- property !== 'source_title' &&
105
- this.block.metadata.config.block_quote[property] !== null &&
106
- this.block.metadata.config.block_quote[property] !== ''
107
- ) {
108
- if (counter > 0) {
109
- //not first hit so a comma is needed before key
110
- counter = counter + 1
111
- this.finalcitation =
112
- this.finalcitation +
113
- ', ' +
114
- this.block.metadata.config.block_quote[property]
115
- } else {
116
- //first hit, no comma needed
117
- counter = counter + 1
118
- this.finalcitation =
119
- '—' +
120
- this.finalcitation +
121
- this.block.metadata.config.block_quote[property]
122
- }
123
- // checks that source_type isn't none and there is a source title
124
- } else if (
125
- property === 'source_title' &&
126
- this.block.metadata.config.block_quote['source_type'] !==
127
- 'None' &&
128
- this.block.metadata.config.block_quote[property] !== null &&
129
- this.block.metadata.config.block_quote[property] !== ''
130
- ) {
131
- // filters out source types book. Adds class to italicize books
132
- if (
133
- this.block.metadata.config.block_quote[
134
- 'source_type'
135
- ] === 'Book'
136
- ) {
137
- // checks if comma needed or not
138
- if (counter > 0) {
139
- this.finalsource =
140
- ', ' +
141
- this.block.metadata.config.block_quote[property]
142
- this.classCitation = 'span-title'
143
- } else {
144
- this.finalsource =
145
- '—' +
146
- this.block.metadata.config.block_quote[property]
147
- this.classCitation = 'span-title'
148
- }
149
- //checks if online journal
150
- } else if (
151
- this.block.metadata.config.block_quote[
152
- 'source_type'
153
- ] === 'Online Journal'
154
- ) {
155
- // checks if comma needed or not. Not Italicized
156
- if (counter > 0) {
157
- this.finalsource =
158
- ', ' +
159
- '"' +
160
- this.block.metadata.config.block_quote[
161
- property
162
- ] +
163
- '"'
164
- this.classCitation = ''
165
- } else {
166
- this.finalsource =
167
- '—' +
168
- '"' +
108
+ source() {
109
+ const parts = []
110
+
111
+ const sourceTitle =
112
+ this.block.metadata.config.block_quote['source_title'] || ''
113
+ const sourceType =
114
+ this.block.metadata.config.block_quote['source_type'] || ''
115
+
116
+ if (sourceTitle && sourceType) {
117
+ switch (sourceType) {
118
+ case 'online_journal':
119
+ // Wrap the sourceTitle for online journals in quotes
120
+ parts.push('"' + sourceTitle + '"')
121
+
122
+ // For online journals also add the url if it exists
123
+ if (
124
+ this.block.metadata.config.block_quote['source_url']
125
+ ) {
126
+ parts.push(
169
127
  this.block.metadata.config.block_quote[
170
- property
171
- ] +
172
- '"'
173
- this.classCitation = ''
128
+ 'source_url'
129
+ ]
130
+ )
174
131
  }
175
- }
132
+ break
133
+ default:
134
+ // Book sources are not wrapped
135
+ parts.push(sourceTitle)
136
+ break
176
137
  }
177
138
  }
139
+
140
+ // If the citation is empty (aka we only have sources)
141
+ // and there's sources then prepend with a mdash
142
+ if (parts.length > 0 && this.citation === '') {
143
+ return he.decode('&mdash;') + parts.join(', ')
144
+ } else if (parts.length > 0) {
145
+ // Otherwise there's a citation / no sources. Don't prepend with mdash
146
+ return parts.join(', ')
147
+ } else {
148
+ return ''
149
+ }
150
+ },
151
+ sourceClass() {
152
+ if (
153
+ this.block.metadata.config.block_quote['source_title'] &&
154
+ this.block.metadata.config.block_quote['source_type'] &&
155
+ this.block.metadata.config.block_quote['source_type'] === 'book'
156
+ ) {
157
+ return 'span-title'
158
+ }
178
159
  },
179
160
  },
161
+ mounted() {},
162
+ methods: {},
180
163
  }
181
164
  </script>
182
165
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <v-container>
3
+ <v-container class="pa-0">
4
4
  <h2>{{ block.metadata.config.title }}</h2>
5
5
 
6
6
  <h4>{{ block.metadata.config.description }}</h4>
@@ -13,14 +13,15 @@
13
13
  }}
14
14
  </p>
15
15
  </v-container>
16
- <v-container>
16
+ <v-container class="pa-0">
17
17
  <v-row
18
18
  v-for="(item, itemIndex) in block.metadata.config.items"
19
19
  :key="itemIndex"
20
20
  no-gutters
21
21
  :class="rowClass(itemIndex)"
22
+ class="pa-0"
22
23
  >
23
- <v-col cols="12" v-bind="iconColumnAttrs" class="pa-4">
24
+ <v-col cols="12" v-bind="iconColumnAttrs">
24
25
  <button
25
26
  :class="activatorButtonClass(itemIndex)"
26
27
  @click="item.active = !item.active"
@@ -144,14 +145,14 @@ export default {
144
145
  if (this.block.metadata.config.display.large_icon) {
145
146
  return {
146
147
  xl: '3',
147
- lg: '4',
148
+ lg: '3',
148
149
  md: '4',
149
150
  sm: '4',
150
151
  }
151
152
  } else {
152
153
  return {
153
154
  xl: '2',
154
- lg: '3',
155
+ lg: '2',
155
156
  md: '3',
156
157
  sm: '3',
157
158
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <v-container>
3
- <v-container v-if="!doesFeedbackExist">
3
+ <v-container v-if="!doesFeedbackExist" class="pa-0">
4
4
  <v-row>
5
5
  <h2>
6
6
  {{
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <v-list>
3
+ <v-list-item
4
+ v-for="(item, index) in value"
5
+ :key="item.file.id + '-' + index"
6
+ :data-activator="'file-link-item-' + index"
7
+ class="pa-0"
8
+ dense
9
+ @click="onClickFile(item)"
10
+ >
11
+ <v-list-item-icon class="mx-3">
12
+ <v-icon>mdi-file-download</v-icon>
13
+ </v-list-item-icon>
14
+
15
+ <v-list-item-content class="text-link py-0"
16
+ >{{ filename(item) }}
17
+ </v-list-item-content>
18
+
19
+ <v-tooltip
20
+ left
21
+ eager
22
+ :activator="'[data-activator=file-link-item-' + index + ']'"
23
+ >
24
+ <span>{{ item.file.asset.metadata.size | humanFilesize }}</span>
25
+ </v-tooltip>
26
+ </v-list-item>
27
+ </v-list>
28
+ </template>
29
+
30
+ <script>
31
+ import _ from 'lodash'
32
+ import Download from '~/helpers/Download'
33
+
34
+ export default {
35
+ name: 'DisplayFileLinks',
36
+ components: {},
37
+ props: {
38
+ value: {
39
+ type: Array,
40
+ required: false,
41
+ default: () => {
42
+ return []
43
+ },
44
+ },
45
+ },
46
+ data() {
47
+ return {
48
+ Download,
49
+ }
50
+ },
51
+ computed: {
52
+ filename() {
53
+ return (item) => {
54
+ const extension = _.get(
55
+ item,
56
+ 'file.asset.metadata.extension',
57
+ ''
58
+ )
59
+ let filename = ''
60
+ // Resolve the filename from either the user defined or from the fileasset itself
61
+ if (item.name) {
62
+ // If we're defining a custom name make sure the file has the extension on it so users know what it is
63
+ filename = item.name
64
+ filename =
65
+ filename.replace(new RegExp(extension + '$'), '') +
66
+ '.' +
67
+ extension
68
+ } else {
69
+ filename = item.file.name || item.file.asset.name
70
+ }
71
+ return filename
72
+ }
73
+ },
74
+ },
75
+ mounted() {},
76
+ methods: {
77
+ onClickFile(item) {
78
+ Download.url(item.file.asset.public_url, this.filename(item))
79
+ },
80
+ },
81
+ }
82
+ </script>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <v-card>
3
+ <v-card-text>
4
+ <v-simple-table>
5
+ <template #default>
6
+ <thead>
7
+ <tr>
8
+ <th>
9
+ {{ $t('shared.file.name') }}
10
+ </th>
11
+ <th>
12
+ {{ $t('shared.file.size') }}
13
+ </th>
14
+ <th>
15
+ {{ $t('shared.file.download') }}
16
+ </th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <tr
21
+ v-for="(item, index) in value"
22
+ :key="item.file.id + '-' + index"
23
+ >
24
+ <td>
25
+ {{ filename(item) }}
26
+ </td>
27
+ <td>
28
+ {{
29
+ item.file.asset.metadata.size
30
+ | humanFilesize
31
+ }}
32
+ </td>
33
+ <td>
34
+ <v-btn
35
+ link
36
+ elevation="0"
37
+ @click="
38
+ Download.url(
39
+ item.file.asset.public_url,
40
+ item.file.name
41
+ )
42
+ "
43
+ >
44
+ <v-icon>mdi-download</v-icon>
45
+ <span class="sr-only">
46
+ {{ $t('shared.file.download') }}
47
+ </span>
48
+ </v-btn>
49
+ </td>
50
+ </tr>
51
+ </tbody>
52
+ </template>
53
+ </v-simple-table>
54
+ </v-card-text>
55
+ </v-card>
56
+ </template>
57
+
58
+ <script>
59
+ import _ from 'lodash'
60
+ import Download from '~/helpers/Download'
61
+
62
+ export default {
63
+ name: 'DisplayFilesTable',
64
+ components: {},
65
+ props: {
66
+ value: {
67
+ type: Array,
68
+ required: false,
69
+ default: () => {
70
+ return []
71
+ },
72
+ },
73
+ },
74
+ data() {
75
+ return {
76
+ Download,
77
+ }
78
+ },
79
+ computed: {
80
+ filename() {
81
+ return (item) => {
82
+ const extension = _.get(
83
+ item,
84
+ 'file.asset.metadata.extension',
85
+ ''
86
+ )
87
+ let filename = ''
88
+ // Resolve the filename from either the user defined or from the fileasset itself
89
+ if (item.name) {
90
+ // If we're defining a custom name make sure the file has the extension on it so users know what it is
91
+ filename = item.name
92
+ filename =
93
+ filename.replace(new RegExp(extension + '$'), '') +
94
+ '.' +
95
+ extension
96
+ } else {
97
+ filename = item.file.name || item.file.asset.name
98
+ }
99
+ return filename
100
+ }
101
+ },
102
+ },
103
+ mounted() {},
104
+ methods: {},
105
+ }
106
+ </script>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <v-container>
3
+ <h2>
4
+ {{
5
+ block.metadata.config.title ||
6
+ $t(
7
+ 'windward.core.components.content.blocks.file_download.default_title'
8
+ )
9
+ }}
10
+ </h2>
11
+ <p v-if="!block.metadata.config.instructions">
12
+ {{
13
+ $t(
14
+ 'windward.core.components.content.blocks.file_download.default_instructions'
15
+ )
16
+ }}
17
+ </p>
18
+ <TextViewer
19
+ v-if="block.metadata.config.instructions"
20
+ :value="block.metadata.config.instructions"
21
+ />
22
+ <v-alert
23
+ v-if="
24
+ !block.metadata.config.items ||
25
+ block.metadata.config.items.length === 0
26
+ "
27
+ type="warning"
28
+ >
29
+ {{
30
+ $t(
31
+ 'windward.core.components.content.blocks.file_download.no_files'
32
+ )
33
+ }}
34
+ </v-alert>
35
+ <FileTable
36
+ v-if="
37
+ block.metadata.config.display_detailed &&
38
+ block.metadata.config.items &&
39
+ block.metadata.config.items.length !== 0
40
+ "
41
+ :value="resolvedItemAssets"
42
+ ></FileTable>
43
+ <FileLinks
44
+ v-if="
45
+ !block.metadata.config.display_detailed &&
46
+ block.metadata.config.items &&
47
+ block.metadata.config.items.length !== 0
48
+ "
49
+ :value="resolvedItemAssets"
50
+ ></FileLinks>
51
+ </v-container>
52
+ </template>
53
+
54
+ <script>
55
+ import _ from 'lodash'
56
+ import { mapGetters } from 'vuex'
57
+ import TextViewer from '~/components/Text/TextViewer'
58
+ import TextEditor from '~/components/Text/TextEditor'
59
+ import Download from '~/helpers/Download'
60
+
61
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
62
+ import FileTable from './FileDownload/FileTable.vue'
63
+ import FileLinks from './FileDownload/FileLinks.vue'
64
+
65
+ export default {
66
+ name: 'FileDownloadBlock',
67
+ components: {
68
+ TextEditor,
69
+ TextViewer,
70
+ FileTable,
71
+ FileLinks,
72
+ },
73
+ extends: BaseContentBlock,
74
+ data() {
75
+ return {
76
+ Download,
77
+ saveState: false, // Override the base block to disable state saving
78
+ valid: true,
79
+ loading: false,
80
+ uploadFiles: [],
81
+ userFileAsset: {},
82
+ studentUpload: null,
83
+ maxFileLimit: 10,
84
+ }
85
+ },
86
+ computed: {
87
+ ...mapGetters({
88
+ enrollment: 'enrollment/get',
89
+ }),
90
+ resolvedItemAssets() {
91
+ const items = []
92
+ for (const index in this.block.metadata.config.items) {
93
+ // Skip items missing a file since we're probably adding a new one in the settings
94
+ if (_.isEmpty(this.block.metadata.config.items[index].file)) {
95
+ continue
96
+ }
97
+
98
+ const item = {
99
+ name: this.block.metadata.config.items[index].name,
100
+ file: this.resolveAsset(
101
+ this.block.metadata.config.items[index].file
102
+ ),
103
+ }
104
+ items.push(item)
105
+ }
106
+
107
+ return items
108
+ },
109
+ },
110
+ beforeMount() {
111
+ if (_.isEmpty(this.block)) {
112
+ this.block = {}
113
+ }
114
+ if (_.isEmpty(this.block.body)) {
115
+ this.block.body = this.$t(
116
+ 'windward.core.shared.content_blocks.title.file_download'
117
+ )
118
+ }
119
+ if (_.isEmpty(this.block.metadata)) {
120
+ this.block.metadata = {}
121
+ }
122
+ if (_.isEmpty(this.block.metadata.config)) {
123
+ this.block.metadata.config = {}
124
+ }
125
+ if (_.isEmpty(this.block.metadata.config.title)) {
126
+ this.block.metadata.config.title = this.$t(
127
+ 'windward.core.components.content.blocks.file_download.default_title'
128
+ )
129
+ }
130
+ if (_.isEmpty(this.block.metadata.config.instructions)) {
131
+ this.block.metadata.config.instructions = this.$t(
132
+ 'windward.core.components.content.blocks.file_download.default_instructions'
133
+ )
134
+ }
135
+ if (!_.isBoolean(this.block.metadata.config.display_detailed)) {
136
+ this.block.metadata.config.display_detailed = false
137
+ }
138
+ if (_.isEmpty(this.block.metadata.config.items)) {
139
+ this.block.metadata.config.items = []
140
+ }
141
+ },
142
+ mounted() {},
143
+ methods: {},
144
+ }
145
+ </script>