@windward/core 0.0.5 → 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 (116) hide show
  1. package/README.md +2 -1
  2. package/components/Content/Blocks/ClickableIcons.vue +10 -1
  3. package/components/Content/Blocks/Feedback.vue +12 -4
  4. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.vue +10 -9
  5. package/components/Content/Blocks/Image.vue +1 -6
  6. package/components/Content/Blocks/OpenResponse.vue +137 -0
  7. package/components/Content/Blocks/OpenResponseCollate.vue +158 -0
  8. package/components/Navigation/Items/AskTheExpert.vue +173 -0
  9. package/components/Settings/ClickableIconsSettings.vue +10 -5
  10. package/components/Settings/OpenResponseCollateSettings.vue +170 -0
  11. package/components/Settings/OpenResponseSettings.vue +81 -0
  12. package/components/utils/ContentViewer.vue +15 -4
  13. package/components/utils/FillInBlank/FillInBlankInput.vue +208 -0
  14. package/components/utils/FillInBlank/FillInTheBlanksManager.vue +98 -0
  15. package/components/utils/MathExpressionEditor.vue +8 -6
  16. package/components/utils/TinyMCEWrapper.vue +59 -9
  17. package/components/utils/assets/tinymce/css/content.scss +9 -0
  18. package/components/utils/glossary/CourseGlossary.vue +12 -8
  19. package/components/utils/glossary/CourseGlossaryForm.vue +24 -5
  20. package/helpers/FillInBlankHelper.ts +55 -0
  21. package/helpers/GlossaryHelper.ts +4 -4
  22. package/helpers/tinymce/plugin.ts +99 -4
  23. package/i18n/en-US/components/content/blocks/feedback.ts +3 -0
  24. package/i18n/en-US/components/content/blocks/index.ts +4 -0
  25. package/i18n/en-US/components/content/blocks/open_response.ts +5 -0
  26. package/i18n/en-US/components/content/blocks/open_response_collate.ts +6 -0
  27. package/i18n/en-US/components/index.ts +0 -1
  28. package/i18n/en-US/components/navigation/ask_the_expert.ts +11 -0
  29. package/i18n/en-US/components/navigation/index.ts +2 -0
  30. package/i18n/en-US/components/settings/index.ts +5 -1
  31. package/i18n/en-US/components/settings/open_response.ts +5 -0
  32. package/i18n/en-US/components/settings/open_response_collate.ts +6 -0
  33. package/i18n/en-US/components/utils/FillInBlank/FillInBlankInput.ts +13 -0
  34. package/i18n/en-US/components/utils/FillInBlank/FillInTheBlanksManager.ts +11 -0
  35. package/i18n/en-US/components/utils/FillInBlank/index.ts +6 -0
  36. package/i18n/en-US/components/utils/index.ts +2 -1
  37. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +1 -0
  38. package/i18n/en-US/shared/content_blocks.ts +2 -0
  39. package/i18n/en-US/shared/menu.ts +1 -0
  40. package/i18n/en-US/shared/settings.ts +3 -1
  41. package/i18n/es-ES/components/content/blocks/feedback.ts +29 -0
  42. package/i18n/es-ES/components/content/blocks/image.ts +5 -0
  43. package/i18n/es-ES/components/content/blocks/index.ts +19 -0
  44. package/i18n/es-ES/components/content/blocks/open_response.ts +6 -0
  45. package/i18n/es-ES/components/content/blocks/open_response_collate.ts +6 -0
  46. package/i18n/es-ES/components/content/blocks/tab.ts +4 -0
  47. package/i18n/es-ES/components/content/blocks/table.ts +4 -0
  48. package/i18n/es-ES/components/content/blocks/user_upload.ts +13 -0
  49. package/i18n/es-ES/components/content/blocks/video.ts +55 -0
  50. package/i18n/es-ES/components/content/index.ts +5 -0
  51. package/i18n/es-ES/components/index.ts +12 -0
  52. package/i18n/es-ES/components/navigation/ask_the_expert.ts +11 -0
  53. package/i18n/es-ES/components/navigation/image.ts +4 -0
  54. package/i18n/es-ES/components/navigation/index.ts +7 -0
  55. package/i18n/es-ES/components/navigation/user_upload.ts +3 -0
  56. package/i18n/es-ES/components/settings/clickable_icon.ts +10 -0
  57. package/i18n/es-ES/components/settings/image.ts +1 -0
  58. package/i18n/es-ES/components/settings/index.ts +17 -0
  59. package/i18n/es-ES/components/settings/open_response.ts +5 -0
  60. package/i18n/es-ES/components/settings/open_response_collate.ts +7 -0
  61. package/i18n/es-ES/components/settings/text_editor.ts +7 -0
  62. package/i18n/es-ES/components/settings/user_upload.ts +11 -0
  63. package/i18n/es-ES/components/settings/video.ts +13 -0
  64. package/i18n/es-ES/components/utils/index.ts +5 -0
  65. package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +18 -0
  66. package/i18n/es-ES/index.ts +16 -0
  67. package/i18n/es-ES/modules/index.ts +5 -0
  68. package/i18n/es-ES/pages/glossary.ts +7 -0
  69. package/i18n/es-ES/pages/index.ts +7 -0
  70. package/i18n/es-ES/pages/user_upload.ts +3 -0
  71. package/i18n/es-ES/shared/content_blocks.ts +22 -0
  72. package/i18n/es-ES/shared/index.ts +11 -0
  73. package/i18n/es-ES/shared/menu.ts +3 -0
  74. package/i18n/es-ES/shared/permission.ts +15 -0
  75. package/i18n/es-ES/shared/settings.ts +19 -0
  76. package/i18n/sv-SE/components/content/blocks/feedback.ts +29 -0
  77. package/i18n/sv-SE/components/content/blocks/image.ts +5 -0
  78. package/i18n/sv-SE/components/content/blocks/index.ts +19 -0
  79. package/i18n/sv-SE/components/content/blocks/open_response.ts +6 -0
  80. package/i18n/sv-SE/components/content/blocks/open_response_collate.ts +6 -0
  81. package/i18n/sv-SE/components/content/blocks/tab.ts +4 -0
  82. package/i18n/sv-SE/components/content/blocks/table.ts +4 -0
  83. package/i18n/sv-SE/components/content/blocks/user_upload.ts +13 -0
  84. package/i18n/sv-SE/components/content/blocks/video.ts +53 -0
  85. package/i18n/sv-SE/components/content/index.ts +5 -0
  86. package/i18n/sv-SE/components/index.ts +12 -0
  87. package/i18n/sv-SE/components/navigation/ask_the_expert.ts +11 -0
  88. package/i18n/sv-SE/components/navigation/image.ts +4 -0
  89. package/i18n/sv-SE/components/navigation/index.ts +7 -0
  90. package/i18n/sv-SE/components/navigation/user_upload.ts +3 -0
  91. package/i18n/sv-SE/components/settings/clickable_icon.ts +10 -0
  92. package/i18n/sv-SE/components/settings/image.ts +1 -0
  93. package/i18n/sv-SE/components/settings/index.ts +17 -0
  94. package/i18n/sv-SE/components/settings/open_response.ts +5 -0
  95. package/i18n/sv-SE/components/settings/open_response_collate.ts +6 -0
  96. package/i18n/sv-SE/components/settings/text_editor.ts +7 -0
  97. package/i18n/sv-SE/components/settings/user_upload.ts +11 -0
  98. package/i18n/sv-SE/components/settings/video.ts +13 -0
  99. package/i18n/sv-SE/components/utils/index.ts +5 -0
  100. package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +18 -0
  101. package/i18n/sv-SE/index.ts +16 -0
  102. package/i18n/sv-SE/modules/index.ts +5 -0
  103. package/i18n/sv-SE/pages/glossary.ts +7 -0
  104. package/i18n/sv-SE/pages/index.ts +7 -0
  105. package/i18n/sv-SE/pages/user_upload.ts +3 -0
  106. package/i18n/sv-SE/shared/content_blocks.ts +22 -0
  107. package/i18n/sv-SE/shared/index.ts +11 -0
  108. package/i18n/sv-SE/shared/menu.ts +3 -0
  109. package/i18n/sv-SE/shared/permission.ts +15 -0
  110. package/i18n/sv-SE/shared/settings.ts +17 -0
  111. package/package.json +1 -1
  112. package/plugin.js +68 -0
  113. package/test/Components/Content/Blocks/OpenResponse.spec.js +31 -0
  114. package/test/Components/Content/Blocks/OpenResponseCollate.spec.js +36 -0
  115. package/test/Components/Settings/OpenResponseCollateSettings.spec.js +20 -0
  116. package/test/Components/Settings/OpenResponseSettings.spec.js +20 -0
@@ -14,7 +14,7 @@
14
14
  <script>
15
15
  import _ from 'lodash'
16
16
  import Editor from '@tinymce/tinymce-vue'
17
- import { MathEditorPlugin } from '../../helpers/tinymce/plugin'
17
+ import { WindwardPlugins } from '../../helpers/tinymce/plugin'
18
18
  import contentCss from '!raw-loader!sass-loader!./assets/tinymce/css/content.scss'
19
19
  import Crypto from '~/helpers/Crypto'
20
20
  export default {
@@ -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,11 +61,11 @@ export default {
50
61
  return {
51
62
  height: 500,
52
63
  visual: false,
53
- menubar: 'file edit insert format view table help',
64
+ menubar: this.menubar,
54
65
  menu: {
55
66
  insert: {
56
67
  title: 'Insert',
57
- items: ' link inserttable | charmap | anchor | math | insertdatetime',
68
+ items: ' link inserttable | charmap | anchor | math | FIB | insertdatetime',
58
69
  },
59
70
  table: {
60
71
  title: 'Table',
@@ -65,10 +76,9 @@ export default {
65
76
  'advlist autolink lists link charmap',
66
77
  'searchreplace visualblocks code fullscreen',
67
78
  'anchor insertdatetime ',
68
- 'paste code wordcount table MathEditor ',
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,
@@ -149,8 +159,8 @@ export default {
149
159
  setup() {
150
160
  // Here we can add plugin
151
161
  window.tinymce.PluginManager.add(
152
- 'MathEditor',
153
- MathEditorPlugin
162
+ 'WindwardToolKit',
163
+ WindwardPlugins
154
164
  )
155
165
  },
156
166
  formats: {
@@ -163,6 +173,21 @@ export default {
163
173
  },
164
174
  classes: 'glossary-word',
165
175
  },
176
+ fib: {
177
+ title: this.$t(
178
+ 'windward.core.components.utils.tiny_mce_wrapper.fill_blank'
179
+ ),
180
+ inline: 'span',
181
+ classes: 'windward-fill-blank',
182
+ attributes: {
183
+ contenteditable: 'true',
184
+ 'data-feedback': btoa(
185
+ this.$t(
186
+ 'windward.core.components.utils.fill_in_the_blank.fill_in_blank_input.default.description'
187
+ )
188
+ ),
189
+ },
190
+ },
166
191
  removeformat: [
167
192
  // Configures `clear formatting` to remove the class glossary-word from spans and if the element then becomes empty it's left intact
168
193
  {
@@ -170,15 +195,30 @@ export default {
170
195
  classes: 'glossary-word',
171
196
  remove: 'all',
172
197
  },
198
+ {
199
+ selector: 'span',
200
+ classes: 'windward-fill-blank',
201
+ remove: 'all',
202
+ split: true,
203
+ expand: false,
204
+ deep: true,
205
+ },
173
206
  ],
174
207
  },
175
208
  style_formats: [
209
+ { title: 'Windward formats' },
176
210
  {
177
211
  title: this.$t(
178
212
  'windward.core.components.utils.tiny_mce_wrapper.term'
179
213
  ),
180
214
  format: 'glossary',
181
215
  },
216
+ {
217
+ title: this.$t(
218
+ 'windward.core.components.utils.tiny_mce_wrapper.fill_blank'
219
+ ),
220
+ format: 'fib',
221
+ },
182
222
  ],
183
223
  style_formats_merge: true,
184
224
  placeholder: this.$t(
@@ -188,7 +228,17 @@ export default {
188
228
 
189
229
  skin: this.$vuetify.theme.isDark ? 'oxide-dark' : 'oxide',
190
230
  content_css: this.$vuetify.theme.isDark ? 'dark' : 'default',
191
- content_style: contentCss,
231
+ //we need to inject the glossary style directly
232
+ content_style:
233
+ contentCss +
234
+ ' .glossary-word {\n' +
235
+ ' display: inline-block;\n' +
236
+ ' border-radius: 12px;\n' +
237
+ ' padding: 0px 7px;\n' +
238
+ ' background-color: #ffd269;\n ' +
239
+ ' font-weight: bold;\n' +
240
+ ' color: #1a1d1e;' +
241
+ '}',
192
242
  importcss_append: true,
193
243
  }
194
244
  },
@@ -183,6 +183,15 @@ table {
183
183
  }
184
184
  }
185
185
 
186
+ span.windward-fill-blank{
187
+ display: inline-block;
188
+ cursor: pointer;
189
+ border: 2px solid #206e8c;
190
+ border-radius: 5px;
191
+ padding: 2px 5px;
192
+ margin: 0 2px;
193
+ color: #000000;
194
+ }
186
195
 
187
196
 
188
197
 
@@ -140,14 +140,14 @@ export default {
140
140
  {
141
141
  text: this.$t('windward.core.pages.glossary.term'),
142
142
  align: 'start',
143
- sortable: false,
144
- value: 'glossaryTerms.term',
143
+ sortable: true,
144
+ value: 'term',
145
145
  },
146
146
  {
147
147
  text: this.$t('windward.core.pages.glossary.definition'),
148
148
  align: 'start',
149
149
  sortable: true,
150
- value: 'glossaryTerms.definition',
150
+ value: 'definition',
151
151
  },
152
152
  {
153
153
  text: this.$t(
@@ -155,13 +155,13 @@ export default {
155
155
  ),
156
156
  align: 'start',
157
157
  sortable: true,
158
- value: 'glossaryTerms.alternate_forms',
158
+ value: 'alternate_forms',
159
159
  },
160
160
  {
161
161
  text: this.$t('windward.core.pages.glossary.related_term'),
162
162
  align: 'start',
163
163
  sortable: true,
164
- value: 'glossaryTerms.related_term',
164
+ value: 'related_term',
165
165
  },
166
166
  ],
167
167
  dialog: false,
@@ -207,12 +207,16 @@ export default {
207
207
  } else {
208
208
  this.glossaryTerms.push(this.selectedTerm)
209
209
  }
210
- const course = new Course(this.course)
211
- if (!_.isSet(course.metadata)) {
210
+ const course = new Course(_.cloneDeep(this.course))
211
+ if (
212
+ !course.hasOwnProperty('metadata') ||
213
+ course.metadata === null
214
+ ) {
212
215
  course.metadata = {}
213
216
  course.metadata.glossary = {}
214
217
  }
215
- if (!_.isSet(course.metadata.glossary)) {
218
+
219
+ if (course.metadata.glossary !== undefined) {
216
220
  course.metadata.glossary = this.glossaryTerms
217
221
  }
218
222
  const updatedCourse = await course.save()
@@ -10,19 +10,31 @@
10
10
  <br />
11
11
  <v-textarea
12
12
  v-model="selectedTerm.definition"
13
- :counter="255"
14
13
  :label="$t('windward.core.pages.glossary.definition')"
15
14
  outlined
16
15
  required
17
16
  :rules="validation.definitionRules"
18
17
  ></v-textarea>
19
18
  <br />
20
- <v-textarea
19
+ <v-combobox
21
20
  v-model="selectedTerm.alternate_forms"
22
- :counter="50"
21
+ chips
22
+ clearable
23
23
  :label="$t('windward.core.pages.glossary.alternate_forms')"
24
- outlined
25
- ></v-textarea>
24
+ multiple
25
+ solo
26
+ >
27
+ <template v-slot:selection="{ attrs, item, select, selected }">
28
+ <v-chip
29
+ v-bind="attrs"
30
+ :input-value="selected"
31
+ close
32
+ @click:close="removeAlternateForm(item)"
33
+ >
34
+ <strong>{{ item }}</strong>
35
+ </v-chip>
36
+ </template>
37
+ </v-combobox>
26
38
  <br />
27
39
  <v-select
28
40
  v-model="selectedTerm.related_term"
@@ -97,6 +109,13 @@ export default {
97
109
  return true
98
110
  }
99
111
  },
112
+ removeAlternateForm(form) {
113
+ const index = this.selectedTerm.alternate_forms.indexOf(form)
114
+ if (index > -1) {
115
+ // only splice array when item is found
116
+ this.selectedTerm.alternate_forms.splice(index, 1) // 2nd parameter means remove one item only
117
+ }
118
+ },
100
119
  },
101
120
  }
102
121
  </script>
@@ -0,0 +1,55 @@
1
+ import * as _ from "lodash";
2
+ import GlossaryTerm from "~/helpers/GlossaryTerm";
3
+
4
+ export default class FillInBlankHelper {
5
+
6
+ private static FillBlankRegex = /<span.*?.class="windward-fill-blank".*?>(.*?)<\/span>/gi;
7
+
8
+ public static containsFillInBlank(content: string): boolean {
9
+ const regex = new RegExp(this.FillBlankRegex);
10
+
11
+ return regex.exec(content) !== null;
12
+ }
13
+
14
+ public static makeToolTip(htmlString: string): string {
15
+ const parser = new DOMParser();
16
+ const doc = parser.parseFromString(htmlString, "text/html");
17
+ // doc.body.firstChild can be null
18
+ let answer = doc.body.firstChild ? doc.body.firstChild.textContent : "";
19
+ let feedback = "";
20
+ if (doc.body.getElementsByClassName("windward-fill-blank")[0]["dataset"]["feedback"] !== undefined) {
21
+ feedback = doc.body.getElementsByClassName("windward-fill-blank")[0]["dataset"]["feedback"];
22
+ }
23
+
24
+ return (
25
+ "<plugin-core-fill-in-blank-input answer=\"" + answer + "\" description=\"" + feedback + "\">" +
26
+ "</template>" + "</plugin-core-fill-in-blank-input>");
27
+
28
+ }
29
+
30
+ public escapeHtml(html) {
31
+ var text = document.createTextNode(html);
32
+ var p = document.createElement("p");
33
+ p.appendChild(text);
34
+ return p.innerHTML;
35
+ }
36
+
37
+ public static renderFillInTHeBlankHtml(content: string, glossary: any) {
38
+ const regex = new RegExp(this.FillBlankRegex);
39
+
40
+
41
+ let match;
42
+ while ((match = regex.exec(content)) !== null) {
43
+ // This is necessary to avoid infinite loops with zero-width matches
44
+ if (match.index === regex.lastIndex) {
45
+ regex.lastIndex++;
46
+ }
47
+ content = content.replace(
48
+ match[0],
49
+ this.makeToolTip(match[0])
50
+ );
51
+ }
52
+
53
+ return content;
54
+ }
55
+ }
@@ -38,13 +38,13 @@ export default class GlossaryHelper {
38
38
 
39
39
  }
40
40
  public static containsGlossaryTerms(content :string): boolean {
41
- const regex = this.glossaryRegex
41
+ const regex = new RegExp(this.glossaryRegex)
42
42
 
43
43
  return regex.exec(content) !== null
44
44
  }
45
45
 
46
46
  public static getContentVerifiedGlossaryTerms(content :string, glossary :any) {
47
- const regex = this.glossaryRegex
47
+ const regex = new RegExp( this.glossaryRegex)
48
48
  const currentGlossary = glossary
49
49
 
50
50
  let match
@@ -74,7 +74,7 @@ export default class GlossaryHelper {
74
74
  }
75
75
 
76
76
  public static getContentUnVerifiedGlossaryTerms(content :string, glossary :any) {
77
- const regex = this.glossaryRegex
77
+ const regex = new RegExp( this.glossaryRegex)
78
78
 
79
79
  let match
80
80
  const verifiedTerms = this.getContentVerifiedGlossaryTerms(content,glossary)
@@ -110,7 +110,7 @@ export default class GlossaryHelper {
110
110
  return unVerifiedTerms
111
111
  }
112
112
  public static renderGlossaryWordsHtml(content :string, glossary :any) {
113
- const regex = this.glossaryRegex
113
+ const regex = new RegExp( this.glossaryRegex)
114
114
  const currentGlossary = glossary
115
115
 
116
116
  let match
@@ -1,5 +1,6 @@
1
- const MathEditorPlugin = function (editor: any) {
1
+ const WindwardPlugins = function (editor: any) {
2
2
  let formula: any
3
+ let fillInBlank: any
3
4
  // ----- Events ----- //
4
5
  editor.ui.registry.addIcon('insertMath', '<svg x="0px" y="0px"width="20px" height="20px" viewBox="0 0 445.878 445.878" style="enable-background:new 0 0 445.878 445.878;">' +
5
6
  '<path d="M426.024,86.447H209.705l-84.911,298.911c-2.568,7.967-9.854,13.482-18.22,13.771c-0.236,0-0.464,0.006-0.688,0.006 c-8.092,0-15.41-4.924-18.436-12.478l-34.714-86.782H19.851C8.884,299.876,0,290.986,0,280.022 c0-10.965,8.893-19.854,19.851-19.854H66.18c8.109,0,15.421,4.941,18.436,12.483l19.237,48.09l72.472-260.218 c2.639-8.213,10.279-13.781,18.903-13.781h230.798c10.97,0,19.854,8.89,19.854,19.851S436.988,86.447,426.024,86.447z M436.723,353.227l-78.259-87.904l74.576-82.783c1.318-1.454,1.638-3.547,0.857-5.341c-0.804-1.791-2.577-2.946-4.54-2.946h-47.18 c-1.442,0-2.802,0.629-3.759,1.72l-50.059,58.047l-49.674-58.029c-0.939-1.103-2.317-1.738-3.771-1.738h-49.334 c-1.956,0-3.729,1.149-4.521,2.929c-0.81,1.785 0.479,3.875,0.824,5.332l73.743,82.81l-77.641,87.923 c-1.297,1.465-1.605,3.552 0.813,5.325c0.813,1.785,2.586,2.92,4.528,2.92h48.9c1.472,0,2.867-0.65,3.807-1.785l51.819-62.181 l53.05,62.229c0.951,1.11,2.328,1.743,3.782,1.743h49.97c1.962,0,3.735-1.141,4.527-2.926 C438.354,356.779,438.035,354.692,436.723,353.227z"/>' +
@@ -41,7 +42,7 @@ const MathEditorPlugin = function (editor: any) {
41
42
  formula = message.content
42
43
  break
43
44
  case 'math-plugin-mounted':
44
- window.parent.postMessage({ latex: data.latex }, '*')
45
+ window.postMessage({ latex: data.latex ?? '' }, '*')
45
46
  break
46
47
  }
47
48
  },
@@ -63,6 +64,11 @@ const MathEditorPlugin = function (editor: any) {
63
64
  })
64
65
  editor.on('init', function () {
65
66
  setOnClickEquationContent(editor)
67
+ setOnClickFillInBlank(editor)
68
+ })
69
+ editor.on('change', function () {
70
+ setOnClickEquationContent(editor)
71
+ setOnClickFillInBlank(editor)
66
72
  })
67
73
  function setOnClickEquationContent(editor: any) {
68
74
  const tinymceDoc = editor.getDoc()
@@ -86,7 +92,96 @@ const MathEditorPlugin = function (editor: any) {
86
92
  }
87
93
  }
88
94
  }
89
- }
90
95
 
91
96
 
92
- export { MathEditorPlugin }
97
+ editor.addCommand('fib-window', function (data: any) {
98
+
99
+ return editor.windowManager.openUrl({
100
+ url: '/plugins/tinymce/FIB',
101
+ title: 'Fill in the blank',
102
+ width: 1024,
103
+ height: 768,
104
+ buttons: [
105
+ {
106
+ type: 'cancel',
107
+ text: 'cancel',
108
+ },
109
+ {
110
+ type: 'custom',
111
+ text: 'submit',
112
+ primary: true,
113
+ },
114
+ ],
115
+ onAction: () => {
116
+ if (data.currentTarget) {
117
+ editor.selection.select(data.currentTarget);
118
+ }
119
+ editor.selection.setContent(
120
+ `<span class='windward-fill-blank' data-feedback =`+ fillInBlank.feedback +` >` +
121
+ fillInBlank.answer +
122
+ `</span>`
123
+ )
124
+
125
+ editor.windowManager.close()
126
+ setOnClickFillInBlank(editor);
127
+ },
128
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
129
+ onMessage: (instance: any, message: any) => {
130
+ switch (message.mceAction) {
131
+ case 'fib-insert':
132
+ fillInBlank = { answer: message.content.answer, feedback: message.content.feedback }
133
+ break
134
+ case 'fib-plugin-mounted':
135
+ window.parent.postMessage({ answer: data.answer ,
136
+ feedback: data.feedback, }, '*')
137
+ break
138
+ }
139
+ },
140
+ })
141
+ })
142
+
143
+ editor.ui.registry.addIcon('insertFIB', '<svg width="20px" height="20px" viewBox="0 0 24 24"><path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20Z" /></svg>' );
144
+ /* Add a button that opens a window */
145
+ editor.ui.registry.addButton('fibButton', {
146
+ icon: 'insertFIB',
147
+ onAction: function () {
148
+ /* Open window */
149
+ editor.execCommand('fib-window', true)
150
+
151
+ }
152
+ });
153
+ editor.ui.registry.addMenuItem('FIB', {
154
+ text: 'FIll in the blank',
155
+ icon: 'insertFIB',
156
+ onAction: () => {
157
+ editor.execCommand('fib-window', true)
158
+ },
159
+ })
160
+
161
+ function setOnClickFillInBlank(editor: any) {
162
+ const tinymceDoc = editor.getDoc()
163
+ const mqSpan = tinymceDoc.getElementsByClassName(
164
+ 'windward-fill-blank'
165
+ )
166
+
167
+ // Add onclick listener to all equation content
168
+ for (const fib of mqSpan) {
169
+ fib.contentEditable = 'true'
170
+ if (fib.onclick) {
171
+ continue
172
+ }
173
+
174
+ fib.onclick = (event: any) => {
175
+ event.stopPropagation()
176
+ editor.execCommand('fib-window', {
177
+ answer: event.target.innerText,
178
+ feedback: event.target.getAttribute('data-feedback'),
179
+ currentTarget: event.target,
180
+ })
181
+ }
182
+ }
183
+ }
184
+
185
+ }
186
+
187
+ export { WindwardPlugins }
@@ -4,6 +4,8 @@ export default {
4
4
  module: 'Module',
5
5
  preset: 'Presets',
6
6
  likert: 'Add standart likert questions',
7
+ likert_directions:
8
+ 'Click to choose first option and then use tab to switch button groups and then arrows to navigate between options.',
7
9
  contact_mindedge: 'Contact Mindedge question',
8
10
  open_response: 'Open Response',
9
11
  response_prompt: 'Provide course feedback below',
@@ -14,6 +16,7 @@ export default {
14
16
  fill_out: 'Please fill out all fields',
15
17
  yes: 'Yes',
16
18
  no: 'No',
19
+ enter: 'Enter Text',
17
20
  description:
18
21
  "This feedback form is optional. However, we would love to hear your thoughts on this learning experience. We take your feedback very seriously, reading and reviewing each entry every day, and we are always trying to improve. Thank you for any comments you'd like to share.",
19
22
  sent_feedback:
@@ -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,7 +3,6 @@ import settings from './settings'
3
3
  import navigation from './navigation/index'
4
4
  import utils from './utils/index'
5
5
 
6
-
7
6
  export default {
8
7
  content,
9
8
  settings,
@@ -0,0 +1,11 @@
1
+ export default {
2
+ ask_expert: 'Ask the Expert',
3
+ config: 'Configuration',
4
+ recipient_email: 'Recipient Email',
5
+ course_info: 'Course and Page Name',
6
+ student_section: 'Student Section',
7
+ subject: 'Subject',
8
+ question: 'Question',
9
+ description:
10
+ 'Ask an expert a question that is specific to the course content',
11
+ }
@@ -1,7 +1,9 @@
1
+ import ask_the_expert from './ask_the_expert'
1
2
  import user_upload from './user_upload'
2
3
  import image from './image'
3
4
 
4
5
  export default {
5
6
  user_upload,
6
7
  image,
8
+ ask_the_expert,
7
9
  }
@@ -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
+ }
@@ -0,0 +1,13 @@
1
+ export default {
2
+ add_answer: 'Add Answer',
3
+ answer: 'Answer',
4
+ check: 'Check',
5
+ check_answer: 'Click to check answer',
6
+ close: 'Close',
7
+ correct: 'Correct',
8
+ default_description: 'default description',
9
+ incorrect: 'Incorrect',
10
+ input_incorrect: "'{0}' is incorrect",
11
+ reset: 'reset',
12
+ try_again: 'Try Again',
13
+ }
@@ -0,0 +1,11 @@
1
+ export default {
2
+ close: 'Close',
3
+ try_again: 'Try Again',
4
+ correct: 'Correct',
5
+ incorrect: 'Incorrect',
6
+ reset: 'reset',
7
+ check: 'Check',
8
+ add_answer: 'Add Answer',
9
+ default_description: 'default description',
10
+ answer: 'Answer',
11
+ }
@@ -0,0 +1,6 @@
1
+ import fill_in_blank_input from './FillInBlankInput'
2
+ import fill_in_the_blank_manager from './FillInTheBlanksManager'
3
+ export default {
4
+ fill_in_blank_input,
5
+ fill_in_the_blank_manager,
6
+ }
@@ -1,5 +1,6 @@
1
1
  import tiny_mce_wrapper from './tiny_mce_wrapper'
2
-
2
+ import fill_in_the_blank from './FillInBlank/index'
3
3
  export default {
4
4
  tiny_mce_wrapper,
5
+ fill_in_the_blank,
5
6
  }
@@ -4,6 +4,7 @@ export default {
4
4
  alternate_forms: 'Alternate Forms',
5
5
  definition: 'definition',
6
6
  related_terms: 'related terms',
7
+ fill_blank: 'Fill in the blank',
7
8
  table: {
8
9
  default: 'Default Table',
9
10
  default_white_line: 'Default Table white lines',
@@ -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,3 +1,4 @@
1
1
  export default {
2
2
  course_glossary: 'Course Glossary',
3
+ ask_the_expert: 'Ask the Expert',
3
4
  }