@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
@@ -0,0 +1,335 @@
1
+
2
+
3
+ /**
4
+ * Class representing the WindwardPlugins.
5
+ */
6
+ export class WindwardPlugins {
7
+ editor: any
8
+ formula: any
9
+ fillInBlank: any
10
+ private window: any;
11
+
12
+ constructor(editor: any) {
13
+
14
+ this.editor = editor
15
+ this.formula = undefined
16
+ this.fillInBlank = undefined
17
+ this.window = window
18
+ this.register()
19
+ }
20
+
21
+
22
+ /**
23
+ * registers an icon with the given icon name and SVG path.
24
+ *
25
+ * @param {string} iconName - The name of the icon.
26
+ * @param {string} svgPath - The SVG path for the icon.
27
+ *
28
+ * @return {void}
29
+ */
30
+ private registerIcon(iconName: string, svgPath: string) {
31
+ this.editor.ui.registry.addIcon(
32
+ iconName,
33
+ svgPath
34
+ )
35
+ }
36
+ /**
37
+ * Adds icons to the editor's UI registry.
38
+ */
39
+ private addIcons() {
40
+ this.registerIcon('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;"><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"/></svg>');
41
+ this.registerIcon('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>');
42
+ this.registerIcon('glossaryIcon', '<svg viewBox="0 0 24 24" width="20px" height="20px" ><path d="M3,15H1V3A2,2 0 0,1 3,1H19V3H3V15M12,23A1,1 0 0,1 11,22V19H7A2,2 0 0,1 5,17V7A2,2 0 0,1 7,5H21A2,2 0 0,1 23,7V17A2,2 0 0,1 21,19H16.9L13.2,22.71C13,22.89 12.76,23 12.5,23H12M9,9V11H19V9H9M9,13V15H17V13H9Z"></path></svg>');
43
+ }
44
+ /**
45
+ * Opens the equation editor window in the TinyMCE editor.
46
+ * @return {void}
47
+ */
48
+ private equationWindow() {
49
+ this.editor.addCommand('equation-window', (data: any) => {
50
+ return this.editor.windowManager.openUrl({
51
+ url: '/plugins/tinymce/math',
52
+ width: .75*this.window.innerWidth,
53
+ height: .9*this.window.innerHeight,
54
+ title: 'Equation editor',
55
+ buttons: [
56
+ {
57
+ type: 'cancel',
58
+ text: 'cancel',
59
+ },
60
+ {
61
+ type: 'custom',
62
+ text: 'submit',
63
+ primary: true,
64
+ },
65
+ ],
66
+ onAction: () => {
67
+ if (data.currentTarget) {
68
+ this.editor.selection.select(data.currentTarget)
69
+ }
70
+ this.editor.selection.setContent(
71
+ ` <span class='windward-math-content'>` +
72
+ this.formula +
73
+ `</span> `
74
+ )
75
+
76
+ this.editor.windowManager.close()
77
+ this.setOnDoubleClickEquationContent(this.editor)
78
+ },
79
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
80
+ onMessage: (instance: any, message: any) => {
81
+ switch (message.mceAction) {
82
+ case 'equation-insert':
83
+ this.formula = message.content
84
+ break
85
+ case 'math-plugin-mounted':
86
+ this.window.postMessage({ latex: data.latex ?? '' }, '*')
87
+ break
88
+ }
89
+ },
90
+ })
91
+ })
92
+ }
93
+
94
+ /**
95
+ * Adds custom buttons to the editor's user interface registry.
96
+ */
97
+ private addButtons() {
98
+
99
+ this.addButtonToEditor(
100
+ "mathButton",
101
+ "insertMath",
102
+ () => {
103
+ this.editor.execCommand("equation-window", true);
104
+ }
105
+ );
106
+ this.addButtonToEditor(
107
+ "glossaryButton",
108
+ "glossaryIcon",
109
+ () => {
110
+ this.editor.formatter.apply("glossary");
111
+ }
112
+ );
113
+ this.addButtonToEditor(
114
+ "fibInsertButton",
115
+ "insertFIB",
116
+ () => {
117
+ this.editor.execCommand("fib-window", true);
118
+ }
119
+ );
120
+ this.addButtonToEditor(
121
+ "fibFormatButton",
122
+ "insertFIB",
123
+ () => {
124
+ this.editor.formatter.apply("fib");
125
+ }
126
+ );
127
+ }
128
+
129
+ /**
130
+ * Add a button to the editor's UI registry
131
+ * @param {string} name Name of the button
132
+ * @param {string} icon Icon name of the button
133
+ * @param {() => void} onAction Callback function for the action to be done when the button is clicked
134
+ */
135
+ private addButtonToEditor(name: string, icon: string, onAction: () => void) {
136
+ this.editor.ui.registry.addButton(name, {
137
+ icon: icon,
138
+ onAction: onAction
139
+ });
140
+ }
141
+ /**
142
+ * Adds a menu item to the editor's UI registry.
143
+ *
144
+ * @param itemKey - The key that uniquely identifies the menu item.
145
+ * @param itemText - The text for the menu item.
146
+ * @param command - The command to be executed on item click.
147
+ * @param icon - The command to be executed on item click.
148
+ * @returns {void}
149
+ */
150
+ private addEditorMenuItem(itemKey: string, itemText: string, command: string, icon: string): void {
151
+ this.editor.ui.registry.addMenuItem(itemKey, {
152
+ text: itemText,
153
+ icon: icon,
154
+ onAction: () => {
155
+ this.editor.execCommand(command, true)
156
+ },
157
+ });
158
+ }
159
+
160
+ /**
161
+ * Adds menu items to the editor UI registry.
162
+ * @returns {void}
163
+ */
164
+ private addMenuItems() {
165
+ this.addEditorMenuItem('math', 'Math', 'equation-window','insertMath');
166
+ this.addEditorMenuItem('FIB', 'Fill in the blank', 'fib-window','insertFIB');
167
+ }
168
+
169
+ /**
170
+ * Initializes the Editor and sets event listeners for 'init' event.
171
+ * Calls setOnClickEquationContent() and setOnClickFillInBlank() methods.
172
+ *
173
+ * @returns {void}
174
+ */
175
+ private init() {
176
+
177
+ this.editor.on('init',()=>{
178
+ this.setOnDoubleClickEquationContent(this.editor)
179
+ this.setOnClickFillInBlank(this.editor)
180
+ })
181
+ }
182
+
183
+ /**
184
+ * Sets the content on the editor and triggers the 'SetContent' event.
185
+ * calls the 'setOnClickEquationContent' and 'setOnClickFillInBlank' methods with the editor as a parameter.
186
+ *
187
+ * @returns {void} This method does not return anything.
188
+ */
189
+ private setContent() {
190
+ this.editor.on('SetContent', () => {
191
+ this.setOnDoubleClickEquationContent(this.editor)
192
+ this.setOnClickFillInBlank(this.editor)
193
+ })
194
+ }
195
+
196
+ /**
197
+ * Adds event listeners for handling input events.
198
+ * @return {void}
199
+ */
200
+ setInputEvents() {
201
+ this.editor.on('input', () =>{
202
+ this.setOnDoubleClickEquationContent(this.editor)
203
+ this.setOnClickFillInBlank(this.editor)
204
+ })
205
+ }
206
+ /**
207
+ * Adds an onclick listener to all equation content within the editor.
208
+ *
209
+ * @param {any} editor - The editor instance.
210
+ */
211
+ setOnDoubleClickEquationContent(editor: any) {
212
+ const tinymceDoc = editor.getDoc()
213
+ const mqSpan = tinymceDoc.getElementsByClassName(
214
+ 'windward-math-content'
215
+ )
216
+
217
+ // Add onclick listener to all equation content
218
+ for (const equationContent of mqSpan) {
219
+ equationContent.contentEditable = 'true'
220
+ if (equationContent.onclick) {
221
+ continue
222
+ }
223
+
224
+ equationContent.ondblclick = (event: any) => {
225
+ event.stopPropagation()
226
+ editor.execCommand('equation-window', {
227
+ latex: event.target.innerText,
228
+ currentTarget: event.target,
229
+ })
230
+ }
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Opens a fill in the blank window in the TinyMCE editor.
236
+ * @return {void}
237
+ */
238
+ fillInBlankWindow() {
239
+ this.editor.addCommand('fib-window', (data: any) => {
240
+ return this.editor.windowManager.openUrl({
241
+ url: '/plugins/tinymce/FIB',
242
+ title: 'Fill in the blank',
243
+ buttons: [
244
+ {
245
+ type: 'cancel',
246
+ text: 'cancel',
247
+ },
248
+ {
249
+ type: 'custom',
250
+ text: 'submit',
251
+ primary: true,
252
+ },
253
+ ],
254
+ onAction: () => {
255
+ if (data.currentTarget) {
256
+ this.editor.selection.select(data.currentTarget)
257
+ }
258
+ this.editor.selection.setContent(
259
+ `<span class='windward-fill-blank' data-feedback =` +
260
+ this.fillInBlank.feedback +
261
+ ` >` +
262
+ this.fillInBlank.answer +
263
+ `</span>`
264
+ )
265
+
266
+ this.editor.windowManager.close()
267
+ this.setOnClickFillInBlank(this.editor)
268
+ },
269
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
270
+ onMessage: (instance: any, message: any) => {
271
+ switch (message.mceAction) {
272
+ case 'fib-insert':
273
+ this.fillInBlank = {
274
+ answer: message.content.answer,
275
+ feedback: message.content.feedback,
276
+ }
277
+ break
278
+ case 'fib-plugin-mounted':
279
+ this.window.parent.postMessage(
280
+ { answer: data.answer, feedback: data.feedback },
281
+ '*'
282
+ )
283
+ break
284
+ }
285
+ },
286
+ })
287
+ })
288
+ }
289
+
290
+ /**
291
+ * Adds an onclick listener to fill-in-blank elements within the provided editor.
292
+ * When a fill-in-blank element is double-clicked, it executes the 'fib-window' command with the appropriate parameters.
293
+ *
294
+ * @param {any} editor - TThe editor instance.
295
+ * @returns {void}
296
+ */
297
+ setOnClickFillInBlank(editor: any) {
298
+ const tinymceDoc = editor.getDoc()
299
+ const mqSpan = tinymceDoc.getElementsByClassName('windward-fill-blank')
300
+
301
+ // Add onclick listener to all equation content
302
+ for (const fib of mqSpan) {
303
+ fib.contentEditable = 'true'
304
+ if (fib.onclick) {
305
+ continue
306
+ }
307
+
308
+ fib.ondblclick = (event: any) => {
309
+ event.stopPropagation()
310
+ editor.execCommand('fib-window', {
311
+ answer: event.target.innerText,
312
+ feedback: event.target.getAttribute('data-feedback'),
313
+ currentTarget: event.target,
314
+ })
315
+ }
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Registers the application, initializing necessary components and setting up the user interface.
321
+ *
322
+ * @return {void}
323
+ */
324
+ private register() {
325
+ this.addIcons()
326
+ this.addButtons()
327
+ this.addMenuItems()
328
+ this.setContent()
329
+ this.setInputEvents()
330
+ this.equationWindow()
331
+ this.fillInBlankWindow()
332
+ this.init()
333
+ }
334
+ }
335
+
@@ -8,10 +8,12 @@ export default {
8
8
  item_color: 'Item Color',
9
9
  item_text: 'Item Text',
10
10
  autocolor: 'Auto-color Options',
11
+ icon_image: 'Use image for icon',
11
12
  display: {
12
13
  show_title: 'Always Show Title',
13
14
  show_background: 'Show Background',
14
15
  round_icon: 'Round Icons',
15
16
  italic_icon: 'Italic Icons',
17
+ large_icon: 'Large Icons',
16
18
  },
17
19
  }
@@ -2,11 +2,16 @@ export default {
2
2
  hide_background: 'Hide Background',
3
3
  modal: 'Click to open in modal',
4
4
  decorative: 'Decorative Image',
5
- toggle_description:
5
+ decorative_toggle_description:
6
6
  'To meet accessibility standards, alt text is required for all images except for purely decorative images. This setting will add the proper alt text and screen reader text for learners.',
7
+ inherit_global_toggle_description:
8
+ 'When enabled, the selected image will use alt text and screen reader text stored on the file, managed in the file manager. When disabled, the selected image will have its own unique alt text and screen reader text that is not shared globally on the file.',
7
9
  alt_description:
8
10
  'Alternative text is descriptive text that conveys the meaning and context of a visual item in a digital setting, intended for users who are visually impaired or otherwise unable to visually identify an image. This should be short and clear.',
9
11
  screenreader: 'Screen Reader Text',
10
12
  screenreader_description:
11
13
  'Screen reader text can be added to give a user using assistive technology more information about the elements on the page',
14
+ inherit: 'Inherit global settings',
15
+ inherit_no_alt: 'No global alt text available for file',
16
+ inherit_no_aria: 'No global screen reader text available for file',
12
17
  }
@@ -17,4 +17,5 @@ export default {
17
17
  subject_report: 'Subject Report',
18
18
  },
19
19
  minimize: 'Minimize',
20
+ read_text_aloud: 'Read Text aloud'
20
21
  }
@@ -22,4 +22,7 @@ export default {
22
22
  instructions: 'Instructions',
23
23
  placeholder: 'Enter text here',
24
24
  },
25
+ upload_file: 'Upload File',
26
+ alt_image: 'Alternate text for image',
27
+ aria_described: 'Aria described by',
25
28
  }
@@ -9,10 +9,12 @@ export default {
9
9
  item_color: 'Color del artículo',
10
10
  item_text: 'Texto del elemento',
11
11
  autocolor: 'Opciones de color automático',
12
+ icon_image: 'Usar imagen como ícono',
12
13
  display: {
13
14
  show_title: 'Mostrar siempre el título',
14
15
  show_background: 'Mostrar fondo',
15
16
  round_icon: 'Iconos redondos',
16
17
  italic_icon: 'Iconos en cursiva',
18
+ large_icon: 'Iconos grandes',
17
19
  },
18
20
  }
@@ -2,11 +2,18 @@ export default {
2
2
  hide_background: 'Ocultar fondo',
3
3
  modal: 'Haga clic para abrir en modal',
4
4
  decorative: 'Imagen decorativa',
5
- toggle_description:
5
+ decorative_toggle_description:
6
6
  'Para cumplir con los estándares de accesibilidad, se requiere texto alternativo para todas las imágenes, excepto para las imágenes puramente decorativas. Esta configuración agregará el texto alternativo y el texto del lector de pantalla adecuados para los estudiantes.',
7
+ inherit_global_toggle_description:
8
+ 'Cuando está habilitado, la imagen seleccionada utilizará texto alternativo y texto del lector de pantalla almacenado en el archivo, administrado en el administrador de archivos. Cuando está deshabilitada, la imagen seleccionada tendrá su propio texto alternativo y texto de lector de pantalla que no se comparte globalmente en el archivo.',
7
9
  alt_description:
8
10
  'El texto alternativo es un texto descriptivo que transmite el significado y el contexto de un elemento visual en un entorno digital, destinado a usuarios con discapacidad visual o que no pueden identificar visualmente una imagen. Esto debe ser breve y claro.',
9
11
  screenreader: 'Texto del lector de pantalla',
10
12
  screenreader_description:
11
13
  'Se puede agregar texto al lector de pantalla para brindarle al usuario que utiliza tecnología de asistencia más información sobre los elementos de la página',
14
+ inherit: 'Heredar configuración global',
15
+ inherit_no_alt:
16
+ 'No hay texto alternativo global disponible para el archivo',
17
+ inherit_no_aria:
18
+ 'No hay texto de lector de pantalla global disponible para el archivo',
12
19
  }
@@ -17,4 +17,5 @@ export default {
17
17
  subject_report: 'Informe de asunto',
18
18
  },
19
19
  minimize: 'Minimizar',
20
+ read_text_aloud: 'Leer texto',
20
21
  }
@@ -24,4 +24,7 @@ export default {
24
24
  instructions: 'Instrucciones',
25
25
  placeholder: 'Ingrese texto aquí',
26
26
  },
27
+ upload_file: 'Subir Archivo',
28
+ alt_image: 'Texto alternativo para imagen',
29
+ aria_described: 'Aria descrita por',
27
30
  }
@@ -9,10 +9,12 @@ export default {
9
9
  item_color: 'Artikelfärg',
10
10
  item_text: 'Artikeltext',
11
11
  autocolor: 'Auto-färgalternativ',
12
+ icon_image: 'Använd bild för ikon',
12
13
  display: {
13
14
  show_title: 'Visa alltid titel',
14
15
  show_background: 'Visa bakgrund',
15
16
  round_icon: 'Runda ikoner',
16
17
  italic_icon: 'Kursiva ikoner',
18
+ large_icon: 'Stora ikoner',
17
19
  },
18
20
  }
@@ -2,11 +2,16 @@ export default {
2
2
  hide_background: 'Dölj bakgrund',
3
3
  modal: 'Klicka för att öppna i modal',
4
4
  decorative: 'Dekorativ bild',
5
- toggle_description:
5
+ decorative_toggle_description:
6
6
  'För att uppfylla tillgänglighetsstandarder krävs alt-text för alla bilder utom för rent dekorativa bilder. Den här inställningen kommer att lägga till rätt alt-text och skärmläsartext för eleverna.',
7
+ inherit_global_toggle_description:
8
+ 'När den är aktiverad kommer den valda bilden att använda alt-text och skärmläsartext lagrad i filen, hanterad i filhanteraren. När den är inaktiverad kommer den valda bilden att ha sin egen unika alt-text och skärmläsartext som inte delas globalt på filen.',
7
9
  alt_description:
8
10
  'Alternativ text är beskrivande text som förmedlar innebörden och sammanhanget av ett visuellt föremål i en digital miljö, avsedd för användare som är synskadade eller på annat sätt oförmögna att visuellt identifiera en bild. Detta ska vara kort och tydligt.',
9
11
  screenreader: 'Skärmläsartext',
10
12
  screenreader_description:
11
13
  'Skärmläsartext kan läggas till för att ge en användare som använder hjälpmedel mer information om elementen på sidan',
14
+ inherit: 'Ärva globala inställningar',
15
+ inherit_no_alt: 'Ingen global alt-text tillgänglig för filen',
16
+ inherit_no_aria: 'Ingen global skärmläsartext tillgänglig för filen',
12
17
  }
@@ -17,4 +17,5 @@ export default {
17
17
  subject_report: 'Ämnesrapport',
18
18
  },
19
19
  minimize: 'Minimera',
20
+ read_text_aloud: 'Läs texten högt',
20
21
  }
@@ -22,4 +22,7 @@ export default {
22
22
  instructions: 'Instruktioner',
23
23
  placeholder: 'Skriv in text här',
24
24
  },
25
+ upload_file: 'Ladda upp fil',
26
+ alt_image: 'Alternativ text till bild',
27
+ aria_described: 'Aria beskrivs av',
25
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Windward UI Core Plugins",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -26,10 +26,12 @@
26
26
  "eslint": "^8.11.0",
27
27
  "he": "^1.2.0",
28
28
  "lodash": "^4.17.21",
29
- "mathlive": "^0.75.0",
30
- "mathml-to-latex": "^1.3.0",
29
+ "mathlive": "^0.98.6",
30
+ "mathml-to-latex": "^1.4.0",
31
31
  "prettier": "^2.6.0",
32
- "raw-loader": "^4.0.2"
32
+ "raw-loader": "^4.0.2",
33
+ "speechreader": "^1.1.5",
34
+ "tinymce": "^7.1.0"
33
35
  },
34
36
  "devDependencies": {
35
37
  "@babel/preset-env": "^7.16.11",
@@ -27,8 +27,22 @@ describe('AccordionSettings', () => {
27
27
  })
28
28
  wrapper.vm.onAddElement()
29
29
  expect(wrapper.vm.$data.block.metadata.config.items).toEqual([
30
- { header: '', expand: false, content: '' },
31
- { header: '', expand: false, content: '' },
30
+ {
31
+ header: '',
32
+ expand: false,
33
+ content: '',
34
+ file: null,
35
+ altText: '',
36
+ ariaDescribedBy: '',
37
+ },
38
+ {
39
+ header: '',
40
+ expand: false,
41
+ content: '',
42
+ file: null,
43
+ altText: '',
44
+ ariaDescribedBy: '',
45
+ },
32
46
  ])
33
47
  })
34
48
 
@@ -59,6 +59,12 @@ jest.mock(
59
59
  resolve(true)
60
60
  })
61
61
  },
62
+ getAssetByFileAssetId(fileAssetId) {
63
+ return null
64
+ },
65
+ resolveAsset(file) {
66
+ return file
67
+ },
62
68
  },
63
69
  }
64
70
  },
@@ -48,6 +48,12 @@ jest.mock(
48
48
  resolve(true)
49
49
  })
50
50
  },
51
+ getAssetByFileAssetId(fileAssetId) {
52
+ return null
53
+ },
54
+ resolveAsset(file) {
55
+ return file
56
+ },
51
57
  },
52
58
  }
53
59
  },
@@ -8,6 +8,7 @@ const text =
8
8
  const mathML =
9
9
  '<math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>+</mo><mfrac><mn>3</mn><mn>4</mn></mfrac></math>'
10
10
  const latexContent = '\\frac{1}{2} + \\frac{3}{4}'
11
+ const latexContentSpeakableText = ' half plus three quarter '
11
12
  const srEnhancedlatex =
12
13
  '**' +
13
14
  JSON.stringify({
@@ -15,7 +16,7 @@ const srEnhancedlatex =
15
16
  sr_text: ' half plus three quarter ',
16
17
  }) +
17
18
  '**'
18
- const mathliveHtml = `<span tabindex="0" aria-label=" half plus three quarter "> <span tabindex="-1" ><span class="ML__mathlive"><span class="ML__strut" style="height:1.33em"></span><span class="ML__strut--bottom" style="height:2.01em;vertical-align:-0.68em"></span><span class="ML__base"><span><span class="mfrac"><span class="nulldelimiter"></span><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.33em"><span class="ML__center" style="top:-2.31em"><span class="pstrut" style="height:3em"></span><span><span class="ML__cmr">2</span></span></span><span style="top:-3.21em"><span class="pstrut" style="height:3em"></span><span class="ML__frac-line"></span></span><span class="ML__center" style="top:-3.67em"><span class="pstrut" style="height:3em"></span><span><span class="ML__cmr">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.69em"></span></span></span><span class="nulldelimiter"></span></span><span class="ML__cmr" style="margin-left:0.23em">+</span><span class="mfrac" style="margin-left:0.23em"><span class="nulldelimiter"></span><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.33em"><span class="ML__center" style="top:-2.31em"><span class="pstrut" style="height:3em"></span><span><span class="ML__cmr">4</span></span></span><span style="top:-3.21em"><span class="pstrut" style="height:3em"></span><span class="ML__frac-line"></span></span><span class="ML__center" style="top:-3.67em"><span class="pstrut" style="height:3em"></span><span><span class="ML__cmr">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.69em"></span></span></span><span class="nulldelimiter"></span></span></span></span></span></span></span>`
19
+ const mathliveHtml = `<span tabindex="0" aria-label=" half plus three quarter "> <span tabindex="-1" ><span class="ML__latex"><span class="ML__strut" style="height:1.15em"></span><span class="ML__strut--bottom" style="height:1.84em;vertical-align:-0.68em"></span><span class="ML__base"><span class="ML__mfrac"><span class="ML__nulldelimiter ML__open" style="width:0.12em"></span><span class="ML__vlist-t ML__vlist-t2"><span class="ML__vlist-r"><span class="ML__vlist" style="height:1.15em"><span class="ML__center" style="top:-2.31em"><span class="ML__pstrut" style="height:3em"></span><span style="height:0.65em;display:inline-block"><span class="ML__cmr">2</span></span></span><span style="top:-3.23em"><span class="ML__pstrut" style="height:3em"></span><span class="ML__frac-line" style="height:0.04em;display:inline-block"></span></span><span class="ML__center" style="top:-3.5em"><span class="ML__pstrut" style="height:3em"></span><span style="height:0.65em;display:inline-block"><span class="ML__cmr">1</span></span></span></span><span class="ML__vlist-s">​</span></span><span class="ML__vlist-r"><span class="ML__vlist" style="height:0.69em"></span></span></span><span class="ML__nulldelimiter ML__close" style="width:0.12em"></span></span><span style="display:inline-block;width:0.23em"></span><span class="ML__cmr">+</span><span style="display:inline-block;width:0.23em"></span><span class="ML__mfrac"><span class="ML__nulldelimiter ML__open" style="width:0.12em"></span><span class="ML__vlist-t ML__vlist-t2"><span class="ML__vlist-r"><span class="ML__vlist" style="height:1.15em"><span class="ML__center" style="top:-2.31em"><span class="ML__pstrut" style="height:3em"></span><span style="height:0.65em;display:inline-block"><span class="ML__cmr">4</span></span></span><span style="top:-3.23em"><span class="ML__pstrut" style="height:3em"></span><span class="ML__frac-line" style="height:0.04em;display:inline-block"></span></span><span class="ML__center" style="top:-3.5em"><span class="ML__pstrut" style="height:3em"></span><span style="height:0.65em;display:inline-block"><span class="ML__cmr">3</span></span></span></span><span class="ML__vlist-s">​</span></span><span class="ML__vlist-r"><span class="ML__vlist" style="height:0.69em"></span></span></span><span class="ML__nulldelimiter ML__close" style="width:0.12em"></span></span></span></span></span></span>`
19
20
  describe('MahtHelper ', () => {
20
21
  test('detects text has mathml', () => {
21
22
  expect(MathHelper.containsMathML(text + mathML)).toBeTruthy()
@@ -98,7 +99,7 @@ describe('MahtHelper ', () => {
98
99
  test('detects content wrapped for tinymce', () => {
99
100
  expect(
100
101
  MathHelper.checkMathContentWrappedForTMCE(
101
- `<span class ='windward-math-content'>` +
102
+ `<span class='windward-math-content'>` +
102
103
  srEnhancedlatex +
103
104
  `</span>` +
104
105
  text +
@@ -111,7 +112,7 @@ describe('MahtHelper ', () => {
111
112
  expect(MathHelper.wrapMathContentForTinyMCE(srEnhancedlatex)).toEqual(
112
113
  `<span class ='windward-math-content'>` +
113
114
  srEnhancedlatex +
114
- `</span>`
115
+ `</span> &nbsp;`
115
116
  )
116
117
  })
117
118
  test('can wrap latexContent in math span for tinymce', () => {
@@ -122,7 +123,38 @@ describe('MahtHelper ', () => {
122
123
  '$$' +
123
124
  latexContent +
124
125
  '$$' +
125
- `</span>`
126
+ `</span> &nbsp;`
127
+ )
128
+ })
129
+
130
+ test('can wrap latexContent in math span for tinymce only once', () => {
131
+ expect(
132
+ MathHelper.wrapMathContentForTinyMCE(
133
+ '$$' + latexContent + '$$' + '$$' + latexContent + '$$'
134
+ )
135
+ ).toEqual(
136
+ `<span class ='windward-math-content'>` +
137
+ '$$' +
138
+ latexContent +
139
+ '$$' +
140
+ `</span> &nbsp;` +
141
+ `<span class ='windward-math-content'>` +
142
+ '$$' +
143
+ latexContent +
144
+ '$$' +
145
+ `</span> &nbsp;`
126
146
  )
127
147
  })
148
+ test('can convert latex to speakable text', () => {
149
+ expect(
150
+ MathHelper.convertMathContentToSpeakableText(
151
+ '$$' + latexContent + '$$'
152
+ )
153
+ ).toEqual(` half plus three quarter `)
154
+ })
155
+ test('can convert SR enhanced latex to speakable text', () => {
156
+ expect(
157
+ MathHelper.convertMathContentToSpeakableText(srEnhancedlatex)
158
+ ).toEqual(` half plus three quarter `)
159
+ })
128
160
  })
package/tsconfig.json CHANGED
@@ -6,6 +6,10 @@
6
6
  "noImplicitAny": false,
7
7
  "outDir": "./lib",
8
8
  "strict": true,
9
+ "lib": [
10
+ "ES2021.String",
11
+ "dom"
12
+ ],
9
13
  "paths": {
10
14
  "~/*": ["./*"],
11
15
  "@/*": ["./*"]