@windward/core 0.3.0 → 0.4.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 (63) hide show
  1. package/components/Content/Blocks/Accordion.vue +37 -0
  2. package/components/Content/Blocks/BlockQuote.vue +2 -2
  3. package/components/Content/Blocks/ClickableIcons.vue +108 -21
  4. package/components/Content/Blocks/Email.vue +19 -6
  5. package/components/Content/Blocks/Feedback.vue +12 -5
  6. package/components/Content/Blocks/Image.vue +47 -19
  7. package/components/Content/Blocks/OpenResponse.vue +7 -3
  8. package/components/Content/Blocks/OpenResponseCollate.vue +1 -1
  9. package/components/Content/Blocks/ScenarioChoice.vue +2 -2
  10. package/components/Content/Blocks/UserUpload/DisplayUserFilesTable.vue +2 -0
  11. package/components/Content/Blocks/UserUpload.vue +1 -0
  12. package/components/Content/Blocks/Video.vue +82 -11
  13. package/components/Navigation/Items/AskTheExpert.vue +1 -0
  14. package/components/Settings/AccordionSettings.vue +55 -0
  15. package/components/Settings/ClickableIconsSettings.vue +89 -8
  16. package/components/Settings/EmailSettings.vue +6 -10
  17. package/components/Settings/FeedbackSettings.vue +1 -0
  18. package/components/Settings/ImageSettings.vue +142 -39
  19. package/components/Settings/MathSettings.vue +1 -1
  20. package/components/Settings/OpenResponseSettings.vue +1 -2
  21. package/components/Settings/ScenarioChoiceSettings.vue +1 -0
  22. package/components/Settings/TabSettings.vue +7 -1
  23. package/components/Settings/TextEditorSettings.vue +3 -2
  24. package/components/Settings/UserUploadSettings.vue +1 -1
  25. package/components/Settings/VideoSettings.vue +102 -63
  26. package/components/utils/ContentViewer.vue +6 -1
  27. package/components/utils/FillInBlank/FillInBlankInput.vue +3 -0
  28. package/components/utils/MathExpressionEditor.vue +37 -11
  29. package/components/utils/MathLiveWrapper.vue +47 -25
  30. package/components/utils/TinyMCEWrapper.vue +214 -34
  31. package/components/utils/assets/tinymce/content/dark/content.scss +4 -0
  32. package/components/utils/assets/tinymce/{css/content.scss → content/global.scss} +38 -37
  33. package/components/utils/assets/tinymce/content/light/content.scss +4 -0
  34. package/components/utils/assets/tinymce/ui/dark/content.scss +803 -0
  35. package/components/utils/assets/tinymce/ui/dark/skin.scss +4727 -0
  36. package/components/utils/assets/tinymce/ui/global.scss +19 -0
  37. package/components/utils/assets/tinymce/ui/light/content.scss +822 -0
  38. package/components/utils/assets/tinymce/ui/light/skin.scss +4731 -0
  39. package/components/utils/glossary/CourseGlossary.vue +3 -1
  40. package/config/tinymce.config.ts +32 -20
  41. package/helpers/FillInBlankHelper.ts +34 -28
  42. package/helpers/GlossaryHelper.ts +90 -73
  43. package/helpers/MathHelper.ts +108 -28
  44. package/helpers/tinymce/WindwardPlugins.ts +335 -0
  45. package/i18n/en-US/components/settings/clickable_icon.ts +2 -0
  46. package/i18n/en-US/components/settings/image.ts +6 -1
  47. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +1 -0
  48. package/i18n/en-US/shared/settings.ts +3 -0
  49. package/i18n/es-ES/components/settings/clickable_icon.ts +2 -0
  50. package/i18n/es-ES/components/settings/image.ts +8 -1
  51. package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +1 -0
  52. package/i18n/es-ES/shared/settings.ts +3 -0
  53. package/i18n/sv-SE/components/settings/clickable_icon.ts +2 -0
  54. package/i18n/sv-SE/components/settings/image.ts +6 -1
  55. package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +1 -0
  56. package/i18n/sv-SE/shared/settings.ts +3 -0
  57. package/package.json +6 -4
  58. package/test/Components/Settings/AccordionSettings.spec.js +16 -2
  59. package/test/__mocks__/contentBlockMock.js +6 -0
  60. package/test/__mocks__/contentSettingsMock.js +6 -0
  61. package/test/helpers/MathHelper.spec.js +36 -4
  62. package/tsconfig.json +4 -0
  63. package/helpers/tinymce/plugin.ts +0 -208
@@ -1,11 +1,15 @@
1
1
  <template>
2
2
  <div :class="'tinymce-included-' + seed">
3
- <div>
4
- <editor
5
- :key="seed + config.skin"
3
+ <div
4
+ :class="
5
+ 'windward-tinymce-wrapper windward-tinymce-wrapper' +
6
+ (isDarkTheme ? '--theme-dark' : '--theme-light')
7
+ "
8
+ >
9
+ <Editor
10
+ :key="seed + (isDarkTheme ? '-theme-dark' : '-theme-light')"
6
11
  v-model="text"
7
12
  initial-value=""
8
- :api-key="api_key"
9
13
  :init="config"
10
14
  tag-name="div"
11
15
  model-events="change keydown blur focus mouseDown paste input submit SetContent"
@@ -16,15 +20,33 @@
16
20
  include,
17
21
  }"
18
22
  >
19
- </editor>
23
+ </Editor>
20
24
  </div>
21
25
 
22
26
  <v-btn-toggle dense multiple class="pt-1 d-flex justify-end">
23
27
  <slot name="actions-prepend" :render="render"></slot>
24
28
  <slot name="actions" :render="render">
29
+ <v-btn-toggle dense>
30
+ <v-btn v-if="render" color="primary" outlined @click="read">
31
+ <v-icon> mdi-play</v-icon>
32
+ </v-btn>
33
+ <v-btn
34
+ v-if="render"
35
+ color="primary"
36
+ outlined
37
+ @click="pause"
38
+ >
39
+ <v-icon> mdi-pause</v-icon>
40
+ </v-btn>
41
+ <v-btn v-if="render" color="primary" outlined @click="stop">
42
+ <v-icon> mdi-stop</v-icon>
43
+ </v-btn>
44
+ </v-btn-toggle>
45
+
25
46
  <v-btn
26
47
  v-if="render"
27
48
  color="primary"
49
+ elevation="0"
28
50
  outlined
29
51
  @click="onClickOutside"
30
52
  >{{
@@ -41,18 +63,71 @@
41
63
 
42
64
  <script>
43
65
  import _ from 'lodash'
66
+ import 'tinymce'
44
67
  import Editor from '@tinymce/tinymce-vue'
45
- import { WindwardPlugins } from '../../helpers/tinymce/plugin'
46
- import contentCss from '!raw-loader!sass-loader!./assets/tinymce/css/content.scss'
68
+ import { getTinymce } from '@tinymce/tinymce-vue/lib/cjs/main/ts/TinyMCE'
69
+
70
+ /* Required TinyMCE components */
71
+ import 'tinymce/icons/default/icons.min.js'
72
+ import 'tinymce/themes/silver/theme.min.js'
73
+ import 'tinymce/models/dom/model.min.js'
74
+
75
+ /* Import a skin (can be a custom skin instead of the default) */
76
+ import 'tinymce/skins/ui/oxide/skin.js'
77
+ import 'tinymce/skins/ui/oxide-dark/skin.js'
78
+
79
+ /* Import plugins */
80
+ import 'tinymce/plugins/accordion'
81
+ import 'tinymce/plugins/advlist'
82
+ import 'tinymce/plugins/anchor'
83
+ import 'tinymce/plugins/autolink'
84
+ import 'tinymce/plugins/autoresize'
85
+ import 'tinymce/plugins/autosave'
86
+ import 'tinymce/plugins/charmap'
87
+ import 'tinymce/plugins/code'
88
+ import 'tinymce/plugins/codesample'
89
+ import 'tinymce/plugins/directionality'
90
+ import 'tinymce/plugins/emoticons'
91
+ import 'tinymce/plugins/fullscreen'
92
+ import 'tinymce/plugins/help'
93
+ import 'tinymce/plugins/image'
94
+ import 'tinymce/plugins/importcss'
95
+ import 'tinymce/plugins/insertdatetime'
96
+ import 'tinymce/plugins/link'
97
+ import 'tinymce/plugins/lists'
98
+ import 'tinymce/plugins/media'
99
+ import 'tinymce/plugins/nonbreaking'
100
+ import 'tinymce/plugins/pagebreak'
101
+ import 'tinymce/plugins/preview'
102
+ import 'tinymce/plugins/quickbars'
103
+ import 'tinymce/plugins/save'
104
+ import 'tinymce/plugins/searchreplace'
105
+ import 'tinymce/plugins/table'
106
+ import 'tinymce/plugins/visualblocks'
107
+ import 'tinymce/plugins/visualchars'
108
+ import 'tinymce/plugins/wordcount'
109
+
110
+ /* content UI CSS is required */
111
+ import 'tinymce/skins/ui/oxide/content.js'
112
+ import 'tinymce/skins/ui/oxide-dark/content.js'
113
+
114
+ /* The default content CSS can be changed or replaced with appropriate CSS for the editor content. */
115
+ import 'tinymce/skins/content/default/content.js'
116
+ import 'tinymce/skins/content/dark/content.js'
117
+
118
+ import { WindwardPlugins } from '../../helpers/tinymce/WindwardPlugins'
119
+ import ContentCss from '!raw-loader!sass-loader!./assets/tinymce/content/global.scss'
120
+ import EditorCss from '!raw-loader!sass-loader!./assets/tinymce/ui/global.scss'
47
121
  import Crypto from '~/helpers/Crypto'
122
+ import MathHelper from '../../helpers/MathHelper'
123
+ import { Synthesizer } from 'speechreader'
48
124
  export default {
49
125
  name: 'ContentEditorRichText',
50
126
  components: {
51
- editor: Editor,
127
+ Editor,
52
128
  },
53
129
  props: {
54
130
  value: { type: String, required: true, default: '' },
55
- api_key: { type: String, required: true, default: '' },
56
131
  height: { type: Number, required: false, default: null },
57
132
  menubar: {
58
133
  type: String,
@@ -63,19 +138,25 @@ export default {
63
138
  type: String,
64
139
  required: false,
65
140
  default:
66
- 'undo redo | formatselect | fontsizeselect | bold italic underline strikethrough removeformat | alignleft aligncenter alignright | table bullist numlist outdent indent | glossaryButton fibButton mathButton ',
141
+ 'undo redo | styles | bold italic underline strikethrough removeformat | alignleft aligncenter alignright | table bullist numlist outdent indent | glossaryButton fibFormatButton mathButton ',
67
142
  },
68
143
  root_block: { type: String, required: false, default: 'div' },
69
144
  label: { type: String, required: true, default: '' },
70
145
  },
71
146
  beforeMount() {
72
- this.text = this.value
147
+ if (MathHelper.containsLatex(this.value)) {
148
+ this.text = MathHelper.wrapMathContentForTinyMCE(this.value)
149
+ } else {
150
+ this.text = this.value
151
+ }
73
152
  },
74
153
  data() {
75
154
  return {
76
155
  render: false,
77
156
  text: '',
78
157
  seed: Crypto.id(),
158
+ synthesizer: null,
159
+ paused: false,
79
160
  }
80
161
  },
81
162
  watch: {
@@ -84,6 +165,9 @@ export default {
84
165
  },
85
166
  },
86
167
  computed: {
168
+ isDarkTheme() {
169
+ return this.$vuetify.theme.isDark
170
+ },
87
171
  filteredMenubar() {
88
172
  if (this.render) {
89
173
  return this.menubar
@@ -114,9 +198,17 @@ export default {
114
198
  visual: false,
115
199
  forced_root_block: this.root_block,
116
200
  menubar: this.filteredMenubar,
201
+ toolbar_mode: 'sliding',
117
202
  browser_spellcheck: true,
118
203
  contextmenu: false,
119
204
  statusbar: false,
205
+ promotion: false,
206
+ license_key: 'gpl',
207
+ ui_mode: 'split',
208
+ dialog_type: 'modal',
209
+ body_class: this.isDarkTheme
210
+ ? 'editor--theme-dark'
211
+ : 'editor--theme-light',
120
212
  menu: {
121
213
  insert: {
122
214
  title: 'Insert',
@@ -132,10 +224,21 @@ export default {
132
224
  },
133
225
  },
134
226
  plugins: [
135
- 'advlist autolink lists link charmap',
136
- 'searchreplace visualblocks code fullscreen',
137
- 'anchor insertdatetime ',
138
- 'paste code wordcount table WindwardToolKit',
227
+ 'advlist',
228
+ 'autolink',
229
+ 'lists',
230
+ 'link',
231
+ 'charmap',
232
+ 'searchreplace',
233
+ 'visualblocks',
234
+ 'code',
235
+ 'fullscreen',
236
+ 'anchor',
237
+ 'insertdatetime',
238
+ 'code',
239
+ 'wordcount',
240
+ 'table',
241
+ 'WindwardToolKit',
139
242
  ],
140
243
  toolbar: this.filteredToolbar,
141
244
  table_advtab: false,
@@ -219,9 +322,11 @@ export default {
219
322
  ],
220
323
  setup() {
221
324
  // Here we can add plugin
222
- window.tinymce.PluginManager.add(
325
+ getTinymce().PluginManager.add(
223
326
  'WindwardToolKit',
224
- WindwardPlugins
327
+ (editor) => {
328
+ new WindwardPlugins(editor)
329
+ }
225
330
  )
226
331
  },
227
332
 
@@ -268,33 +373,72 @@ export default {
268
373
  ],
269
374
  },
270
375
  style_formats: [
271
- { title: 'Windward formats' },
272
376
  {
273
- title: this.$t(
274
- 'windward.core.components.utils.tiny_mce_wrapper.term'
275
- ),
276
- format: 'glossary',
377
+ title: 'Headings',
378
+ items: [
379
+ { title: 'Heading 2', format: 'h2' },
380
+ { title: 'Heading 3', format: 'h3' },
381
+ { title: 'Heading 4', format: 'h4' },
382
+ { title: 'Heading 5', format: 'h5' },
383
+ { title: 'Heading 6', format: 'h6' },
384
+ ],
277
385
  },
278
386
  {
279
- title: this.$t(
280
- 'windward.core.components.utils.tiny_mce_wrapper.fill_blank'
281
- ),
282
- format: 'fib',
387
+ title: 'Inline',
388
+ items: [
389
+ { title: 'Bold', format: 'bold' },
390
+ { title: 'Italic', format: 'italic' },
391
+ { title: 'Underline', format: 'underline' },
392
+ { title: 'Strikethrough', format: 'strikethrough' },
393
+ { title: 'Superscript', format: 'superscript' },
394
+ { title: 'Subscript', format: 'subscript' },
395
+ { title: 'Code', format: 'code' },
396
+ ],
397
+ },
398
+ {
399
+ title: 'Blocks',
400
+ items: [{ title: 'Paragraph', format: 'p' }],
401
+ },
402
+ {
403
+ title: 'Align',
404
+ items: [
405
+ { title: 'Left', format: 'alignleft' },
406
+ { title: 'Center', format: 'aligncenter' },
407
+ { title: 'Right', format: 'alignright' },
408
+ { title: 'Justify', format: 'alignjustify' },
409
+ ],
410
+ },
411
+ {
412
+ title: 'Windward',
413
+ items: [
414
+ {
415
+ title: this.$t(
416
+ 'windward.core.components.utils.tiny_mce_wrapper.term'
417
+ ),
418
+ format: 'glossary',
419
+ },
420
+ {
421
+ title: this.$t(
422
+ 'windward.core.components.utils.tiny_mce_wrapper.fill_blank'
423
+ ),
424
+ format: 'fib',
425
+ },
426
+ ],
283
427
  },
284
428
  ],
285
- style_formats_merge: true,
286
429
  placeholder: this.label
287
430
  ? this.label
288
431
  : this.$t(
289
432
  'windward.core.shared.settings.title.placeholder'
290
433
  ),
291
434
  //required as it will be displayed as inline style in tinymce renderer
292
-
293
- skin: this.$vuetify.theme.isDark ? 'oxide-dark' : 'oxide',
435
+ skin: false,
294
436
  content_css: this.$vuetify.theme.isDark ? 'dark' : 'default',
437
+
295
438
  //we need to inject the glossary style directly
296
439
  content_style:
297
- contentCss +
440
+ ContentCss +
441
+ EditorCss +
298
442
  ' .glossary-word {\n' +
299
443
  ' display: inline-block;\n' +
300
444
  ' border-radius: 12px;\n' +
@@ -306,7 +450,6 @@ export default {
306
450
  importcss_append: true,
307
451
  }
308
452
  },
309
-
310
453
  elementBody() {
311
454
  const ele = document.querySelector('.tinymce-included-' + this.seed)
312
455
 
@@ -317,6 +460,31 @@ export default {
317
460
  },
318
461
  },
319
462
  methods: {
463
+ read() {
464
+ if (this.paused) {
465
+ this.resume()
466
+ } else {
467
+ this.synthesizer = new Synthesizer(
468
+ MathHelper.convertMathContentToSpeakableText(this.text),
469
+ this.$i18n.locale
470
+ )
471
+ this.synthesizer.play()
472
+ }
473
+ },
474
+ pause() {
475
+ if (!this.paused) {
476
+ this.synthesizer.pause()
477
+ this.paused = true
478
+ }
479
+ },
480
+ resume() {
481
+ this.synthesizer.resume()
482
+ this.paused = false
483
+ },
484
+ stop() {
485
+ this.synthesizer.stop()
486
+ this.paused = false
487
+ },
320
488
  onEditorFocus() {
321
489
  if (!this.render) {
322
490
  this.seed = Crypto.id()
@@ -345,10 +513,11 @@ export default {
345
513
  }
346
514
 
347
515
  if (
348
- parentNode.closest('.tinymce-included-' + this.seed) ||
516
+ (parentNode &&
517
+ (parentNode.closest('.tinymce-included-' + this.seed) ||
518
+ _.includes(parentNode.className, 'tox'))) ||
349
519
  _.includes(targetClass, 'tinymce-included-' + this.seed) ||
350
- _.includes(targetClass, 'tox') ||
351
- _.includes(parentNode.className, 'tox')
520
+ _.includes(targetClass, 'tox')
352
521
  ) {
353
522
  return false
354
523
  } else {
@@ -359,3 +528,14 @@ export default {
359
528
  },
360
529
  }
361
530
  </script>
531
+
532
+ <style lang="scss">
533
+ html:has(body.theme--light) {
534
+ @import './assets/tinymce/ui/light/content.scss';
535
+ @import './assets/tinymce/ui/light/skin.scss';
536
+ }
537
+ html:has(body.theme--dark) {
538
+ @import './assets/tinymce/ui/dark/content.scss';
539
+ @import './assets/tinymce/ui/dark/skin.scss';
540
+ }
541
+ </style>
@@ -0,0 +1,4 @@
1
+ body {
2
+ background-color: #24292a;
3
+ color: #fff;
4
+ }
@@ -1,32 +1,30 @@
1
-
2
1
  table {
3
2
  max-width: 100%;
4
- border: 1px solid var(--v-primary-base) !important;
3
+ border: 1px solid var(--v-primary-base);
5
4
  border-spacing: 0;
6
5
 
7
- th, td {
8
- border: 1px solid var(--v-primary-base) !important;
6
+ th,
7
+ td {
8
+ border: 1px solid var(--v-primary-base);
9
9
  padding: 3px;
10
10
  }
11
-
12
11
  }
13
12
  table {
14
- &.windward-table-default {
15
-
13
+ &.windward-table-default {
16
14
  color: black;
17
15
 
18
16
  th {
19
17
  color: white;
20
18
  padding: 16px;
21
- background-color: #3B4143FF;
19
+ background-color: #3b4143ff;
22
20
  }
23
21
 
24
- th, td {
22
+ th,
23
+ td {
25
24
  text-align: left;
26
25
  border: 1px solid black;
27
26
  }
28
27
 
29
-
30
28
  tr:nth-child(even) {
31
29
  td {
32
30
  background-color: #ffffff;
@@ -35,19 +33,18 @@ table {
35
33
 
36
34
  tr:nth-child(odd) {
37
35
  td {
38
- background-color: #EAEAEC;
36
+ background-color: #eaeaec;
39
37
  }
40
38
  }
41
39
 
42
-
43
- &--lines{
44
- border: 1px solid #ffffff;
45
- th, td {
46
- border: 1px solid #ffffff;
47
- }
48
- }
49
-
50
- }
40
+ &--lines {
41
+ border: 1px solid #ffffff;
42
+ th,
43
+ td {
44
+ border: 1px solid #ffffff;
45
+ }
46
+ }
47
+ }
51
48
 
52
49
  &.windward-table-excel {
53
50
  padding-bottom: 20px;
@@ -62,7 +59,7 @@ table {
62
59
  padding: 3px;
63
60
  text-align: center;
64
61
  color: black;
65
- background-color: #D7CCC8;
62
+ background-color: #d7ccc8;
66
63
  }
67
64
 
68
65
  td {
@@ -70,7 +67,6 @@ table {
70
67
  color: #000;
71
68
  padding: 5px;
72
69
  text-align: left;
73
-
74
70
  }
75
71
  }
76
72
 
@@ -83,23 +79,20 @@ table {
83
79
  background-color: #206e8c;
84
80
  }
85
81
 
86
- th, td {
82
+ th,
83
+ td {
87
84
  text-align: left;
88
-
89
85
  }
90
86
 
91
87
  tr:nth-child(even) {
92
88
  th {
93
89
  border: 1px solid black;
94
-
95
90
  }
96
91
 
97
92
  td {
98
93
  border: 1px solid black;
99
94
  background-color: #ffffff;
100
-
101
95
  }
102
-
103
96
  }
104
97
 
105
98
  tr:nth-child(odd) {
@@ -109,12 +102,11 @@ table {
109
102
 
110
103
  td {
111
104
  border: 1px solid black;
112
- background-color: #EAEAEC;
105
+ background-color: #eaeaec;
113
106
  }
114
107
  }
115
108
  }
116
109
 
117
-
118
110
  /* ledger table */
119
111
  &.windward-table-ledger {
120
112
  &--right-align {
@@ -129,12 +121,12 @@ table {
129
121
  background-color: white;
130
122
  color: black;
131
123
 
132
- thead, th {
124
+ thead,
125
+ th {
133
126
  border: 3px solid black;
134
127
  font-weight: bold;
135
128
  }
136
129
 
137
-
138
130
  tr {
139
131
  td {
140
132
  border: 1px solid black;
@@ -153,7 +145,8 @@ table {
153
145
  font-weight: bold;
154
146
  }
155
147
 
156
- th:last-child, td:last-child {
148
+ th:last-child,
149
+ td:last-child {
157
150
  border-right: 0;
158
151
  }
159
152
 
@@ -170,20 +163,20 @@ table {
170
163
  text-align: left;
171
164
  padding: 11px;
172
165
 
173
- thead, th {
166
+ thead,
167
+ th {
174
168
  font-weight: bold;
175
- background-color: #EAEAEC;
169
+ background-color: #eaeaec;
176
170
  padding: 3px;
177
171
  }
178
172
 
179
173
  td th {
180
174
  border: 1px solid black;
181
175
  }
182
-
183
176
  }
184
177
  }
185
178
 
186
- span.windward-fill-blank{
179
+ span.windward-fill-blank {
187
180
  display: inline-block;
188
181
  cursor: pointer;
189
182
  border: 2px solid #206e8c;
@@ -193,5 +186,13 @@ span.windward-fill-blank{
193
186
  color: #000000;
194
187
  }
195
188
 
196
- body { font-family: 'Roboto', sans-serif; }
189
+ body {
190
+ font-family: 'Roboto', sans-serif;
191
+ }
197
192
 
193
+ html:has(body.editor--theme-light) {
194
+ @import './light/content.scss';
195
+ }
196
+ html:has(body.editor--theme-dark) {
197
+ @import './dark/content.scss';
198
+ }
@@ -0,0 +1,4 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #1a1d1e;
4
+ }