@windward/core 0.4.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 (36) hide show
  1. package/components/Content/Blocks/BlockQuote.vue +2 -2
  2. package/components/Content/Blocks/ClickableIcons.vue +1 -1
  3. package/components/Content/Blocks/Email.vue +10 -6
  4. package/components/Content/Blocks/Feedback.vue +12 -5
  5. package/components/Content/Blocks/OpenResponse.vue +7 -3
  6. package/components/Content/Blocks/OpenResponseCollate.vue +1 -1
  7. package/components/Content/Blocks/ScenarioChoice.vue +2 -2
  8. package/components/Content/Blocks/UserUpload/DisplayUserFilesTable.vue +2 -0
  9. package/components/Content/Blocks/UserUpload.vue +1 -0
  10. package/components/Content/Blocks/Video.vue +2 -2
  11. package/components/Navigation/Items/AskTheExpert.vue +1 -0
  12. package/components/Settings/AccordionSettings.vue +2 -0
  13. package/components/Settings/ClickableIconsSettings.vue +5 -1
  14. package/components/Settings/EmailSettings.vue +6 -1
  15. package/components/Settings/FeedbackSettings.vue +1 -0
  16. package/components/Settings/MathSettings.vue +1 -1
  17. package/components/Settings/ScenarioChoiceSettings.vue +1 -0
  18. package/components/Settings/TabSettings.vue +7 -1
  19. package/components/Settings/TextEditorSettings.vue +3 -2
  20. package/components/Settings/UserUploadSettings.vue +1 -1
  21. package/components/Settings/VideoSettings.vue +2 -0
  22. package/components/utils/FillInBlank/FillInBlankInput.vue +3 -0
  23. package/components/utils/MathExpressionEditor.vue +30 -9
  24. package/components/utils/MathLiveWrapper.vue +47 -25
  25. package/components/utils/TinyMCEWrapper.vue +102 -18
  26. package/components/utils/glossary/CourseGlossary.vue +2 -0
  27. package/config/tinymce.config.ts +17 -13
  28. package/helpers/MathHelper.ts +59 -0
  29. package/helpers/tinymce/WindwardPlugins.ts +335 -0
  30. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +1 -0
  31. package/i18n/es-ES/components/utils/tiny_mce_wrapper.ts +1 -0
  32. package/i18n/sv-SE/components/utils/tiny_mce_wrapper.ts +1 -0
  33. package/package.json +3 -2
  34. package/test/helpers/MathHelper.spec.js +14 -1
  35. package/tsconfig.json +4 -1
  36. package/helpers/tinymce/plugin.ts +0 -210
@@ -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
+
@@ -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
  }
@@ -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
  }
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Windward UI Core Plugins",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -26,10 +26,11 @@
26
26
  "eslint": "^8.11.0",
27
27
  "he": "^1.2.0",
28
28
  "lodash": "^4.17.21",
29
- "mathlive": "^0.75.0",
29
+ "mathlive": "^0.98.6",
30
30
  "mathml-to-latex": "^1.4.0",
31
31
  "prettier": "^2.6.0",
32
32
  "raw-loader": "^4.0.2",
33
+ "speechreader": "^1.1.5",
33
34
  "tinymce": "^7.1.0"
34
35
  },
35
36
  "devDependencies": {
@@ -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()
@@ -144,4 +145,16 @@ describe('MahtHelper ', () => {
144
145
  `</span> &nbsp;`
145
146
  )
146
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
+ })
147
160
  })
package/tsconfig.json CHANGED
@@ -6,7 +6,10 @@
6
6
  "noImplicitAny": false,
7
7
  "outDir": "./lib",
8
8
  "strict": true,
9
- "lib": ["ES2021.String"],
9
+ "lib": [
10
+ "ES2021.String",
11
+ "dom"
12
+ ],
10
13
  "paths": {
11
14
  "~/*": ["./*"],
12
15
  "@/*": ["./*"]
@@ -1,210 +0,0 @@
1
- import MathHelper from "../MathHelper";
2
- const WindwardPlugins = function (editor: any) {
3
- let formula: any
4
- let fillInBlank: any
5
- // ----- Events ----- //
6
- editor.ui.registry.addIcon(
7
- 'insertMath',
8
- '<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;">' +
9
- '<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"/>' +
10
- '</svg>'
11
- )
12
- editor.addCommand('equation-window', function (data: any) {
13
- return editor.windowManager.openUrl({
14
- url: '/plugins/tinymce/math',
15
- title: 'Equation editor',
16
- buttons: [
17
- {
18
- type: 'cancel',
19
- text: 'cancel',
20
- },
21
- {
22
- type: 'custom',
23
- text: 'submit',
24
- primary: true,
25
- },
26
- ],
27
- onAction: () => {
28
- if (data.currentTarget) {
29
- editor.selection.select(data.currentTarget)
30
- }
31
- editor.selection.setContent(
32
- ` <span class='windward-math-content'>` +
33
- formula +
34
- `</span> `
35
- )
36
-
37
- editor.windowManager.close()
38
- setOnClickEquationContent(editor)
39
- },
40
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
- onMessage: (instance: any, message: any) => {
42
- switch (message.mceAction) {
43
- case 'equation-insert':
44
- formula = message.content
45
- break
46
- case 'math-plugin-mounted':
47
- window.postMessage({ latex: data.latex ?? '' }, '*')
48
- break
49
- }
50
- },
51
- })
52
- })
53
-
54
- editor.ui.registry.addButton('mathButton', {
55
- icon: 'insertMath',
56
- onAction: () => {
57
- editor.execCommand('equation-window', true)
58
- },
59
- })
60
- editor.ui.registry.addMenuItem('math', {
61
- text: 'Math',
62
- icon: 'insertMath',
63
- onAction: () => {
64
- editor.execCommand('equation-window', true)
65
- },
66
- })
67
- editor.on('init', function () {
68
- setOnClickEquationContent(editor)
69
- setOnClickFillInBlank(editor)
70
- })
71
-
72
- editor.on('SetContent', function () {
73
- setOnClickEquationContent(editor)
74
- setOnClickFillInBlank(editor)
75
- })
76
- editor.on('input', function () {
77
- setOnClickEquationContent(editor)
78
- setOnClickFillInBlank(editor)
79
- })
80
- function setOnClickEquationContent(editor: any) {
81
- const tinymceDoc = editor.getDoc()
82
- const mqSpan = tinymceDoc.getElementsByClassName(
83
- 'windward-math-content'
84
- )
85
-
86
- // Add onclick listener to all equation content
87
- for (const equationContent of mqSpan) {
88
- equationContent.contentEditable = 'true'
89
- if (equationContent.onclick) {
90
- continue
91
- }
92
-
93
- equationContent.ondblclick = (event: any) => {
94
- event.stopPropagation()
95
- editor.execCommand('equation-window', {
96
- latex: event.target.innerText,
97
- currentTarget: event.target,
98
- })
99
- }
100
- }
101
- }
102
-
103
- editor.addCommand('fib-window', function (data: any) {
104
- return editor.windowManager.openUrl({
105
- url: '/plugins/tinymce/FIB',
106
- title: 'Fill in the blank',
107
- buttons: [
108
- {
109
- type: 'cancel',
110
- text: 'cancel',
111
- },
112
- {
113
- type: 'custom',
114
- text: 'submit',
115
- primary: true,
116
- },
117
- ],
118
- onAction: () => {
119
- if (data.currentTarget) {
120
- editor.selection.select(data.currentTarget)
121
- }
122
- editor.selection.setContent(
123
- `<span class='windward-fill-blank' data-feedback =` +
124
- fillInBlank.feedback +
125
- ` >` +
126
- fillInBlank.answer +
127
- `</span>`
128
- )
129
-
130
- editor.windowManager.close()
131
- setOnClickFillInBlank(editor)
132
- },
133
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
134
- onMessage: (instance: any, message: any) => {
135
- switch (message.mceAction) {
136
- case 'fib-insert':
137
- fillInBlank = {
138
- answer: message.content.answer,
139
- feedback: message.content.feedback,
140
- }
141
- break
142
- case 'fib-plugin-mounted':
143
- window.parent.postMessage(
144
- { answer: data.answer, feedback: data.feedback },
145
- '*'
146
- )
147
- break
148
- }
149
- },
150
- })
151
- })
152
-
153
- editor.ui.registry.addIcon(
154
- 'insertFIB',
155
- '<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>'
156
- )
157
-
158
- editor.ui.registry.addIcon(
159
- 'glossaryIcon',
160
- '<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>'
161
- )
162
-
163
- /* Add a button that opens a window */
164
- editor.ui.registry.addButton('glossaryButton', {
165
- icon: 'glossaryIcon',
166
- onAction: function () {
167
- /* apply format */
168
- editor.formatter.apply('glossary')
169
- },
170
- })
171
- /* Add a button that opens a window */
172
- editor.ui.registry.addButton('fibButton', {
173
- icon: 'insertFIB',
174
- onAction: function () {
175
- /* Open window */
176
- editor.execCommand('fib-window', true)
177
- },
178
- })
179
- editor.ui.registry.addMenuItem('FIB', {
180
- text: 'FIll in the blank',
181
- icon: 'insertFIB',
182
- onAction: () => {
183
- editor.execCommand('fib-window', true)
184
- },
185
- })
186
-
187
- function setOnClickFillInBlank(editor: any) {
188
- const tinymceDoc = editor.getDoc()
189
- const mqSpan = tinymceDoc.getElementsByClassName('windward-fill-blank')
190
-
191
- // Add onclick listener to all equation content
192
- for (const fib of mqSpan) {
193
- fib.contentEditable = 'true'
194
- if (fib.onclick) {
195
- continue
196
- }
197
-
198
- fib.ondblclick = (event: any) => {
199
- event.stopPropagation()
200
- editor.execCommand('fib-window', {
201
- answer: event.target.innerText,
202
- feedback: event.target.getAttribute('data-feedback'),
203
- currentTarget: event.target,
204
- })
205
- }
206
- }
207
- }
208
- }
209
-
210
- export { WindwardPlugins }