@instructure/canvas-rce 5.8.0 → 5.10.0
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.
- package/.mocharc.js +7 -0
- package/CHANGELOG.md +20 -0
- package/es/enhance-user-content/mathml.js +8 -5
- package/es/rce/RCEWrapper.js +65 -6
- package/es/rce/RCEWrapperProps.js +1 -0
- package/es/rce/__mocks__/_mockCryptoEs.js +124 -0
- package/es/rce/plugins/instructure_equation/EquationEditorModal/parseLatex.js +0 -2
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +4 -5
- package/es/rce/plugins/shared/CanvasContentTray.js +8 -8
- package/es/rce/plugins/shared/ContentSelection.js +7 -3
- package/es/rce/plugins/shared/ImageCropper/Preview.js +8 -7
- package/es/rce/plugins/shared/LinkDisplay.js +2 -2
- package/es/rce/plugins/tinymce-a11y-checker/rules/large-text-contrast.js +9 -0
- package/es/rce/plugins/tinymce-a11y-checker/rules/small-text-contrast.js +9 -0
- package/es/translations/locales/da-x-k12.js +39 -0
- package/es/translations/locales/de.js +4 -4
- package/es/translations/locales/fi.js +39 -0
- package/es/translations/locales/nb-x-k12.js +39 -0
- package/es/translations/locales/sv-x-k12.js +39 -0
- package/es/util/encrypted-storage.js +84 -0
- package/jest/jest-setup.js +5 -3
- package/jest.config.js +1 -0
- package/lib/enhance-user-content/mathml.js +8 -5
- package/lib/rce/RCEWrapper.js +65 -6
- package/lib/rce/RCEWrapperProps.js +1 -0
- package/lib/rce/__mocks__/_mockCryptoEs.js +124 -0
- package/lib/rce/plugins/instructure_equation/EquationEditorModal/parseLatex.js +0 -2
- package/lib/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +4 -5
- package/lib/rce/plugins/shared/CanvasContentTray.js +8 -8
- package/lib/rce/plugins/shared/ContentSelection.js +7 -3
- package/lib/rce/plugins/shared/ImageCropper/Preview.js +8 -7
- package/lib/rce/plugins/shared/LinkDisplay.js +2 -2
- package/lib/rce/plugins/tinymce-a11y-checker/rules/large-text-contrast.js +9 -0
- package/lib/rce/plugins/tinymce-a11y-checker/rules/small-text-contrast.js +9 -0
- package/lib/translations/locales/da-x-k12.js +39 -0
- package/lib/translations/locales/de.js +4 -4
- package/lib/translations/locales/fi.js +39 -0
- package/lib/translations/locales/nb-x-k12.js +39 -0
- package/lib/translations/locales/sv-x-k12.js +39 -0
- package/lib/util/encrypted-storage.js +84 -0
- package/package.json +5 -5
- package/es/rce/getBrowser.js +0 -53
- package/lib/rce/getBrowser.js +0 -53
|
@@ -45,6 +45,9 @@ const locale = {
|
|
|
45
45
|
"add_image_60b2de07": {
|
|
46
46
|
"message": "Lisää kuva"
|
|
47
47
|
},
|
|
48
|
+
"add_one_9e34a6f8": {
|
|
49
|
+
"message": "Lisää yksi!"
|
|
50
|
+
},
|
|
48
51
|
"additional_considerations_f3801683": {
|
|
49
52
|
"message": "Muuta huomioon otettavaa"
|
|
50
53
|
},
|
|
@@ -1323,9 +1326,27 @@ const locale = {
|
|
|
1323
1326
|
"no_accessibility_issues_were_detected_f8d3c875": {
|
|
1324
1327
|
"message": "Ei havaittu käytettävyysongelmia."
|
|
1325
1328
|
},
|
|
1329
|
+
"no_announcements_created_yet_c44a94f4": {
|
|
1330
|
+
"message": "Ilmoituksia ei ole vielä luotu."
|
|
1331
|
+
},
|
|
1332
|
+
"no_announcements_found_20185afc": {
|
|
1333
|
+
"message": "Ilmoituksia ei löytynyt."
|
|
1334
|
+
},
|
|
1335
|
+
"no_assignments_created_yet_1b236d87": {
|
|
1336
|
+
"message": "Tehtäviä ei ole vielä luotu."
|
|
1337
|
+
},
|
|
1338
|
+
"no_assignments_found_79e46d7f": {
|
|
1339
|
+
"message": "Tehtäviä ei löytynyt."
|
|
1340
|
+
},
|
|
1326
1341
|
"no_changes_to_save_d29f6e91": {
|
|
1327
1342
|
"message": "Ei tallennettavia muutoksia."
|
|
1328
1343
|
},
|
|
1344
|
+
"no_discussions_created_yet_ff99abe3": {
|
|
1345
|
+
"message": "Keskusteluja ei ole vielä luotu."
|
|
1346
|
+
},
|
|
1347
|
+
"no_discussions_found_9284063b": {
|
|
1348
|
+
"message": "Keskusteluja ei löytynyt."
|
|
1349
|
+
},
|
|
1329
1350
|
"no_e16d9132": {
|
|
1330
1351
|
"message": "Ei"
|
|
1331
1352
|
},
|
|
@@ -1335,9 +1356,27 @@ const locale = {
|
|
|
1335
1356
|
"no_headers_9bc7dc7f": {
|
|
1336
1357
|
"message": "Ei otsikoita"
|
|
1337
1358
|
},
|
|
1359
|
+
"no_modules_created_yet_c71b6d4d": {
|
|
1360
|
+
"message": "Moduuleja ei ole vielä luotu."
|
|
1361
|
+
},
|
|
1362
|
+
"no_modules_found_2df43a40": {
|
|
1363
|
+
"message": "Moduuleja ei löytynyt."
|
|
1364
|
+
},
|
|
1365
|
+
"no_pages_created_yet_c379fa6e": {
|
|
1366
|
+
"message": "Sivuja ei ole vielä luotu"
|
|
1367
|
+
},
|
|
1368
|
+
"no_pages_found_6799350": {
|
|
1369
|
+
"message": "Sivuja ei löytynyt."
|
|
1370
|
+
},
|
|
1338
1371
|
"no_preview_is_available_for_this_file_f940114a": {
|
|
1339
1372
|
"message": "Tälle tiedostolle ei ole saatavissa esikatselua."
|
|
1340
1373
|
},
|
|
1374
|
+
"no_quizzes_created_yet_1a2370b9": {
|
|
1375
|
+
"message": "Testejä ei ole vielä luotu."
|
|
1376
|
+
},
|
|
1377
|
+
"no_quizzes_found_c80c537a": {
|
|
1378
|
+
"message": "Testejä ei löytynyt."
|
|
1379
|
+
},
|
|
1341
1380
|
"no_results_940393cf": {
|
|
1342
1381
|
"message": "Ei tuloksia."
|
|
1343
1382
|
},
|
|
@@ -45,6 +45,9 @@ const locale = {
|
|
|
45
45
|
"add_image_60b2de07": {
|
|
46
46
|
"message": "Legg til bilde"
|
|
47
47
|
},
|
|
48
|
+
"add_one_9e34a6f8": {
|
|
49
|
+
"message": "Legg til en!"
|
|
50
|
+
},
|
|
48
51
|
"additional_considerations_f3801683": {
|
|
49
52
|
"message": "Ekstra hensyn"
|
|
50
53
|
},
|
|
@@ -1323,9 +1326,27 @@ const locale = {
|
|
|
1323
1326
|
"no_accessibility_issues_were_detected_f8d3c875": {
|
|
1324
1327
|
"message": "Ingen tiljengelighetsproblemer ble oppdaget."
|
|
1325
1328
|
},
|
|
1329
|
+
"no_announcements_created_yet_c44a94f4": {
|
|
1330
|
+
"message": "Ingen beskjeder opprettet ennå."
|
|
1331
|
+
},
|
|
1332
|
+
"no_announcements_found_20185afc": {
|
|
1333
|
+
"message": "Ingen beskjeder funnet."
|
|
1334
|
+
},
|
|
1335
|
+
"no_assignments_created_yet_1b236d87": {
|
|
1336
|
+
"message": "Ingen oppgave opprettet ennå."
|
|
1337
|
+
},
|
|
1338
|
+
"no_assignments_found_79e46d7f": {
|
|
1339
|
+
"message": "Ingen oppgaver funnet."
|
|
1340
|
+
},
|
|
1326
1341
|
"no_changes_to_save_d29f6e91": {
|
|
1327
1342
|
"message": "Ingen endringer å lagre."
|
|
1328
1343
|
},
|
|
1344
|
+
"no_discussions_created_yet_ff99abe3": {
|
|
1345
|
+
"message": "Ingen diskusjoner opprettet ennå."
|
|
1346
|
+
},
|
|
1347
|
+
"no_discussions_found_9284063b": {
|
|
1348
|
+
"message": "Ingen diskusjoner funnet."
|
|
1349
|
+
},
|
|
1329
1350
|
"no_e16d9132": {
|
|
1330
1351
|
"message": "Nei"
|
|
1331
1352
|
},
|
|
@@ -1335,9 +1356,27 @@ const locale = {
|
|
|
1335
1356
|
"no_headers_9bc7dc7f": {
|
|
1336
1357
|
"message": "Ingen titler"
|
|
1337
1358
|
},
|
|
1359
|
+
"no_modules_created_yet_c71b6d4d": {
|
|
1360
|
+
"message": "Ingen moduler opprettet ennå."
|
|
1361
|
+
},
|
|
1362
|
+
"no_modules_found_2df43a40": {
|
|
1363
|
+
"message": "Ingen moduler funnet."
|
|
1364
|
+
},
|
|
1365
|
+
"no_pages_created_yet_c379fa6e": {
|
|
1366
|
+
"message": "Ingen sider opprettet ennå."
|
|
1367
|
+
},
|
|
1368
|
+
"no_pages_found_6799350": {
|
|
1369
|
+
"message": "Ingen sider funnet."
|
|
1370
|
+
},
|
|
1338
1371
|
"no_preview_is_available_for_this_file_f940114a": {
|
|
1339
1372
|
"message": "Ingen forhåndsvisning er tilgjengelig for denne filen."
|
|
1340
1373
|
},
|
|
1374
|
+
"no_quizzes_created_yet_1a2370b9": {
|
|
1375
|
+
"message": "Ingen quizer opprettet ennå."
|
|
1376
|
+
},
|
|
1377
|
+
"no_quizzes_found_c80c537a": {
|
|
1378
|
+
"message": "Ingen quizer funnet."
|
|
1379
|
+
},
|
|
1341
1380
|
"no_results_940393cf": {
|
|
1342
1381
|
"message": "Ingen resultater."
|
|
1343
1382
|
},
|
|
@@ -45,6 +45,9 @@ const locale = {
|
|
|
45
45
|
"add_image_60b2de07": {
|
|
46
46
|
"message": "Lägg till bild"
|
|
47
47
|
},
|
|
48
|
+
"add_one_9e34a6f8": {
|
|
49
|
+
"message": "Lägg till en!"
|
|
50
|
+
},
|
|
48
51
|
"additional_considerations_f3801683": {
|
|
49
52
|
"message": "Ytterliggare hänsynstaganden"
|
|
50
53
|
},
|
|
@@ -1323,9 +1326,27 @@ const locale = {
|
|
|
1323
1326
|
"no_accessibility_issues_were_detected_f8d3c875": {
|
|
1324
1327
|
"message": "Inga tillgänglighetsproblem upptäcktes."
|
|
1325
1328
|
},
|
|
1329
|
+
"no_announcements_created_yet_c44a94f4": {
|
|
1330
|
+
"message": "Inga meddelanden har skapats än."
|
|
1331
|
+
},
|
|
1332
|
+
"no_announcements_found_20185afc": {
|
|
1333
|
+
"message": "Inga meddelande hittades."
|
|
1334
|
+
},
|
|
1335
|
+
"no_assignments_created_yet_1b236d87": {
|
|
1336
|
+
"message": "Inga uppgifter har skapats än."
|
|
1337
|
+
},
|
|
1338
|
+
"no_assignments_found_79e46d7f": {
|
|
1339
|
+
"message": "Inga uppgifter hittades."
|
|
1340
|
+
},
|
|
1326
1341
|
"no_changes_to_save_d29f6e91": {
|
|
1327
1342
|
"message": "Inga ändringar att spara."
|
|
1328
1343
|
},
|
|
1344
|
+
"no_discussions_created_yet_ff99abe3": {
|
|
1345
|
+
"message": "Inga diskussioner har skapats än."
|
|
1346
|
+
},
|
|
1347
|
+
"no_discussions_found_9284063b": {
|
|
1348
|
+
"message": "Inga diskussioner hittades."
|
|
1349
|
+
},
|
|
1329
1350
|
"no_e16d9132": {
|
|
1330
1351
|
"message": "Nej"
|
|
1331
1352
|
},
|
|
@@ -1335,9 +1356,27 @@ const locale = {
|
|
|
1335
1356
|
"no_headers_9bc7dc7f": {
|
|
1336
1357
|
"message": "Inga rubriker"
|
|
1337
1358
|
},
|
|
1359
|
+
"no_modules_created_yet_c71b6d4d": {
|
|
1360
|
+
"message": "Inga moduler har skapats än."
|
|
1361
|
+
},
|
|
1362
|
+
"no_modules_found_2df43a40": {
|
|
1363
|
+
"message": "Inga moduler hittades."
|
|
1364
|
+
},
|
|
1365
|
+
"no_pages_created_yet_c379fa6e": {
|
|
1366
|
+
"message": "Inga sidor har skapats än."
|
|
1367
|
+
},
|
|
1368
|
+
"no_pages_found_6799350": {
|
|
1369
|
+
"message": "Inga sidor hittades."
|
|
1370
|
+
},
|
|
1338
1371
|
"no_preview_is_available_for_this_file_f940114a": {
|
|
1339
1372
|
"message": "Förhandsvisning är inte tillgänglig för den här filen."
|
|
1340
1373
|
},
|
|
1374
|
+
"no_quizzes_created_yet_1a2370b9": {
|
|
1375
|
+
"message": "Inga quiz har skapats än."
|
|
1376
|
+
},
|
|
1377
|
+
"no_quizzes_found_c80c537a": {
|
|
1378
|
+
"message": "Inga quiz hittades."
|
|
1379
|
+
},
|
|
1341
1380
|
"no_results_940393cf": {
|
|
1342
1381
|
"message": "Inga resultat."
|
|
1343
1382
|
},
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2023 - present Instructure, Inc.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of Canvas.
|
|
5
|
+
*
|
|
6
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
7
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
8
|
+
* Software Foundation, version 3 of the License.
|
|
9
|
+
*
|
|
10
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
12
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
13
|
+
* details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
16
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import CryptoES from 'crypto-es';
|
|
19
|
+
export default class EncryptedStorage {
|
|
20
|
+
constructor(passphrase) {
|
|
21
|
+
this.passphrase = void 0;
|
|
22
|
+
|
|
23
|
+
this.errorHandlerWrapper = callback => {
|
|
24
|
+
try {
|
|
25
|
+
return callback();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('error', error);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
this.passphrase = CryptoES.enc.Utf8.parse(passphrase);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setItem(key, content) {
|
|
36
|
+
return this.errorHandlerWrapper(() => {
|
|
37
|
+
// If passphrase is present, encrypt string and JSON stringify
|
|
38
|
+
let encrypted;
|
|
39
|
+
|
|
40
|
+
if (this.passphrase) {
|
|
41
|
+
encrypted = CryptoES.RC4.encrypt(content, this.passphrase, {
|
|
42
|
+
mode: CryptoES.mode.CFB,
|
|
43
|
+
padding: CryptoES.pad.AnsiX923
|
|
44
|
+
}).toString();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const data = JSON.stringify({
|
|
48
|
+
autosaveTimestamp: new Date().getTime(),
|
|
49
|
+
content: encrypted
|
|
50
|
+
});
|
|
51
|
+
return window.localStorage.setItem(key, data);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getItem(key) {
|
|
56
|
+
return this.errorHandlerWrapper(() => {
|
|
57
|
+
const data = window.localStorage.getItem(key);
|
|
58
|
+
|
|
59
|
+
if (!data) {
|
|
60
|
+
return data;
|
|
61
|
+
} // If passphrase is present, parse JSON and decrypt string
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if (this.passphrase) {
|
|
65
|
+
const parsedData = JSON.parse(data);
|
|
66
|
+
parsedData.content = CryptoES.RC4.decrypt(parsedData.content, this.passphrase, {
|
|
67
|
+
mode: CryptoES.mode.CFB,
|
|
68
|
+
padding: CryptoES.pad.AnsiX923
|
|
69
|
+
});
|
|
70
|
+
parsedData.content = parsedData.content.toString(CryptoES.enc.Utf8);
|
|
71
|
+
return parsedData;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
key(index) {
|
|
77
|
+
return this.errorHandlerWrapper(() => window.localStorage.key(index));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
removeItem(key) {
|
|
81
|
+
return this.errorHandlerWrapper(() => window.localStorage.removeItem(key));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
package/jest/jest-setup.js
CHANGED
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
// Several components use aphrodite, which tries to manipulate the dom
|
|
20
20
|
// on a timer which expires after the test completes and the document no longer exists
|
|
21
21
|
import {StyleSheetTestUtils} from 'aphrodite'
|
|
22
|
-
import {filterUselessConsoleMessages} from '@instructure/js-utils'
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* We want to ensure errors and warnings get appropriate eyes. If
|
|
@@ -42,8 +41,9 @@ const ignoredErrors = [
|
|
|
42
41
|
/The prop `videoOptions.naturalHeight` is marked as required in `VideoOptionsTray`/,
|
|
43
42
|
/The prop `sortBy.order` is marked as required in `MediaPanel`/,
|
|
44
43
|
/Invalid prop `images.searchString` of type `string` supplied to `Images`/,
|
|
45
|
-
/Invalid URL: undefined/,
|
|
46
44
|
/failed updating video captions/,
|
|
45
|
+
/You seem to have overlapping act\(\) calls/,
|
|
46
|
+
/A theme registry has already been initialized/,
|
|
47
47
|
]
|
|
48
48
|
const globalWarn = global.console.warn
|
|
49
49
|
const ignoredWarnings = [
|
|
@@ -51,6 +51,9 @@ const ignoredWarnings = [
|
|
|
51
51
|
/Found bad LTI MRU data/,
|
|
52
52
|
/Cannot save LTI MRU list/,
|
|
53
53
|
/clicked sidebar (link|image) without a focused editor/,
|
|
54
|
+
/Translation for/,
|
|
55
|
+
/Exactly one focusable child is required/,
|
|
56
|
+
/is deprecated and will be removed/,
|
|
54
57
|
]
|
|
55
58
|
global.console = {
|
|
56
59
|
log: console.log,
|
|
@@ -77,7 +80,6 @@ global.console = {
|
|
|
77
80
|
}
|
|
78
81
|
/* eslint-enable no-console */
|
|
79
82
|
|
|
80
|
-
filterUselessConsoleMessages(console)
|
|
81
83
|
StyleSheetTestUtils.suppressStyleInjection()
|
|
82
84
|
|
|
83
85
|
// because InstUI themeable components need an explicit "dir" attribute on the <html> element
|
package/jest.config.js
CHANGED
|
@@ -47,6 +47,7 @@ module.exports = {
|
|
|
47
47
|
'\\.(css|less)$': '<rootDir>/src/rce/__mocks__/styleMock.js',
|
|
48
48
|
// mock the tinymce-react Editor component
|
|
49
49
|
'@tinymce/tinymce-react': '<rootDir>/src/rce/__mocks__/tinymceReact.jsx',
|
|
50
|
+
'crypto-es': '<rootDir>/src/rce/__mocks__/_mockCryptoEs.ts',
|
|
50
51
|
},
|
|
51
52
|
|
|
52
53
|
transform: {
|
|
@@ -45,7 +45,8 @@ const localConfig = {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
|
-
showMathMenu: true
|
|
48
|
+
showMathMenu: true,
|
|
49
|
+
messageStyle: 'none'
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
class Mathml {
|
|
@@ -106,7 +107,7 @@ class Mathml {
|
|
|
106
107
|
window.MathJax.Hub.Register.MessageHook('Math Processing Error', function (message) {
|
|
107
108
|
var _elem$parentElement;
|
|
108
109
|
|
|
109
|
-
const elem = message[1]; // ".math_equation_latex" is the elem we added for MathJax to typeset the image equation
|
|
110
|
+
const elem = Array.isArray(message[1]) ? message[1][0] : message[1]; // ".math_equation_latex" is the elem we added for MathJax to typeset the image equation
|
|
110
111
|
|
|
111
112
|
if ((_elem$parentElement = elem.parentElement) !== null && _elem$parentElement !== void 0 && _elem$parentElement.classList.contains('math_equation_latex')) {
|
|
112
113
|
var _elem$parentElement$p;
|
|
@@ -123,7 +124,7 @@ class Mathml {
|
|
|
123
124
|
}
|
|
124
125
|
});
|
|
125
126
|
window.MathJax.Hub.Register.MessageHook('End Math', function (message) {
|
|
126
|
-
const elem = message[1];
|
|
127
|
+
const elem = Array.isArray(message[1]) ? message[1][0] : message[1];
|
|
127
128
|
mathImageHelper.removeStrayEquationImages(elem);
|
|
128
129
|
mathImageHelper.nearlyInfiniteStyleFix(elem);
|
|
129
130
|
elem.querySelectorAll('.math_equation_latex').forEach(m => m.classList.add('fade-in-equation'));
|
|
@@ -138,7 +139,8 @@ class Mathml {
|
|
|
138
139
|
// Since we want to ignore <math> in .hidden-readable spans, let's remove the MathJunk™
|
|
139
140
|
// right after MathJax adds it.
|
|
140
141
|
window.MathJax.Hub.Register.MessageHook('End Math', function (message) {
|
|
141
|
-
|
|
142
|
+
const elm = Array.isArray(message[1]) ? message[1][0] : message[1];
|
|
143
|
+
$(elm).find('.hidden-readable [class^="MathJax"], .hidden-readable [id^="MathJax"]').remove();
|
|
142
144
|
});
|
|
143
145
|
} // leaving this here so I don't have to keep looking up how to see all messages
|
|
144
146
|
// window.MathJax.Hub.Startup.signal.Interest(function (message) {
|
|
@@ -315,7 +317,8 @@ const mathImageHelper = {
|
|
|
315
317
|
},
|
|
316
318
|
|
|
317
319
|
catchEquationImages(refnode) {
|
|
318
|
-
// find equation images and replace with inline LaTeX
|
|
320
|
+
refnode = Array.isArray(refnode) ? refnode[0] : refnode; // find equation images and replace with inline LaTeX
|
|
321
|
+
|
|
319
322
|
const eqimgs = refnode.querySelectorAll('img.equation_image');
|
|
320
323
|
|
|
321
324
|
if (eqimgs.length > 0) {
|
package/lib/rce/RCEWrapper.js
CHANGED
|
@@ -2373,6 +2373,7 @@ import { rceWrapperPropTypes } from './RCEWrapperProps';
|
|
|
2373
2373
|
import { insertPlaceholder, placeholderInfoFor, removePlaceholder } from '../util/loadingPlaceholder';
|
|
2374
2374
|
import { transformRceContentForEditing } from './transformContent';
|
|
2375
2375
|
import { IconMoreSolid } from '@instructure/ui-icons/es/svg';
|
|
2376
|
+
import EncryptedStorage from '../util/encrypted-storage';
|
|
2376
2377
|
import buildStyle from './style';
|
|
2377
2378
|
const RestoreAutoSaveModal = /*#__PURE__*/React.lazy(() => import('./RestoreAutoSaveModal'));
|
|
2378
2379
|
const RceHtmlEditor = /*#__PURE__*/React.lazy(() => import('./RceHtmlEditor'));
|
|
@@ -2713,9 +2714,67 @@ class RCEWrapper extends React.Component {
|
|
|
2713
2714
|
|
|
2714
2715
|
this.checkAccessibility();
|
|
2715
2716
|
this.fixToolbarKeyboardNavigation();
|
|
2717
|
+
this.forwardPostMessages();
|
|
2716
2718
|
(_this$props$onInitted = (_this$props = this.props).onInitted) === null || _this$props$onInitted === void 0 ? void 0 : _this$props$onInitted.call(_this$props, editor);
|
|
2717
2719
|
};
|
|
2718
2720
|
|
|
2721
|
+
this.forwardPostMessages = () => {
|
|
2722
|
+
const windowReferences = [];
|
|
2723
|
+
const rceWindow = this.editor.getWin(); // explicitly assign name for reference by parent window
|
|
2724
|
+
|
|
2725
|
+
rceWindow.name = `${RCEWrapper.editorFrameName}_${this.id}`;
|
|
2726
|
+
rceWindow.addEventListener('message', this.forwardPostMessagesHandler(rceWindow, windowReferences));
|
|
2727
|
+
};
|
|
2728
|
+
|
|
2729
|
+
this.forwardPostMessagesHandler = (rceWindow, windowReferences) => e => {
|
|
2730
|
+
let message;
|
|
2731
|
+
|
|
2732
|
+
try {
|
|
2733
|
+
message = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
2734
|
+
} catch (err) {
|
|
2735
|
+
// unparseable message may not be meant for our handlers
|
|
2736
|
+
return false;
|
|
2737
|
+
} // NOTE: the code to encode/decode `sourceToolInfo` is duplicated in
|
|
2738
|
+
// the ui/features/post_message_forwarding/index.ts, and
|
|
2739
|
+
// cannot be DRY'd because RCE is in a package
|
|
2740
|
+
|
|
2741
|
+
|
|
2742
|
+
if (e.origin === rceWindow.origin) {
|
|
2743
|
+
const {
|
|
2744
|
+
sourceToolInfo,
|
|
2745
|
+
...messageWithoutSourceToolInfo
|
|
2746
|
+
} = message;
|
|
2747
|
+
const targetOrigin = sourceToolInfo === null || sourceToolInfo === void 0 ? void 0 : sourceToolInfo.origin;
|
|
2748
|
+
const targetWindow = windowReferences[sourceToolInfo === null || sourceToolInfo === void 0 ? void 0 : sourceToolInfo.windowId];
|
|
2749
|
+
|
|
2750
|
+
if (!targetOrigin || !targetWindow) {
|
|
2751
|
+
return false;
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.postMessage(messageWithoutSourceToolInfo, targetOrigin);
|
|
2755
|
+
} else {
|
|
2756
|
+
// message is from tool, forward to Canvas window
|
|
2757
|
+
// We can't forward the whole `e.source` window in the postMessage,
|
|
2758
|
+
// so we keep a list (`windowReferences`) of all windows we've received
|
|
2759
|
+
// messages from, and include the index into that list as `windowId`
|
|
2760
|
+
let windowId = windowReferences.indexOf(e.source);
|
|
2761
|
+
|
|
2762
|
+
if (windowId === -1) {
|
|
2763
|
+
windowReferences.push(e.source);
|
|
2764
|
+
windowId = windowReferences.length - 1;
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
const newMessage = { ...message,
|
|
2768
|
+
sourceToolInfo: {
|
|
2769
|
+
origin: e.origin,
|
|
2770
|
+
windowId
|
|
2771
|
+
},
|
|
2772
|
+
frameName: rceWindow.name
|
|
2773
|
+
};
|
|
2774
|
+
rceWindow.parent.postMessage(newMessage, rceWindow.origin);
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
|
|
2719
2778
|
this.fixToolbarKeyboardNavigation = () => {
|
|
2720
2779
|
var _this$_elementRef$cur2;
|
|
2721
2780
|
|
|
@@ -2787,7 +2846,9 @@ class RCEWrapper extends React.Component {
|
|
|
2787
2846
|
this.announcing = 0;
|
|
2788
2847
|
|
|
2789
2848
|
this.initAutoSave = editor => {
|
|
2790
|
-
|
|
2849
|
+
var _this$props$userCache;
|
|
2850
|
+
|
|
2851
|
+
this.storage = new EncryptedStorage((_this$props$userCache = this.props.userCacheKey) !== null && _this$props$userCache !== void 0 ? _this$props$userCache : '');
|
|
2791
2852
|
|
|
2792
2853
|
if (this.storage) {
|
|
2793
2854
|
editor.on('change Undo Redo', this.doAutoSave);
|
|
@@ -2875,10 +2936,7 @@ class RCEWrapper extends React.Component {
|
|
|
2875
2936
|
});
|
|
2876
2937
|
|
|
2877
2938
|
try {
|
|
2878
|
-
_this.storage.setItem(_this.autoSaveKey,
|
|
2879
|
-
autosaveTimestamp: Date.now(),
|
|
2880
|
-
content
|
|
2881
|
-
}));
|
|
2939
|
+
_this.storage.setItem(_this.autoSaveKey, content);
|
|
2882
2940
|
} catch (ex) {
|
|
2883
2941
|
if (!retry) {
|
|
2884
2942
|
// probably failed because there's not enough space
|
|
@@ -3733,7 +3791,7 @@ class RCEWrapper extends React.Component {
|
|
|
3733
3791
|
let autosaved = null;
|
|
3734
3792
|
|
|
3735
3793
|
try {
|
|
3736
|
-
autosaved = this.storage &&
|
|
3794
|
+
autosaved = this.storage && this.storage.getItem(key);
|
|
3737
3795
|
} catch (_ex) {
|
|
3738
3796
|
this.storage.removeItem(this.autoSaveKey);
|
|
3739
3797
|
}
|
|
@@ -4199,6 +4257,7 @@ RCEWrapper.defaultProps = {
|
|
|
4199
4257
|
canvasOrigin: ''
|
|
4200
4258
|
};
|
|
4201
4259
|
RCEWrapper.skinCssInjected = false;
|
|
4260
|
+
RCEWrapper.editorFrameName = 'active_rce_frame';
|
|
4202
4261
|
|
|
4203
4262
|
function mergeMenuItems(standard, custom) {
|
|
4204
4263
|
var _custom$trim;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2023 - present Instructure, Inc.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of Canvas.
|
|
5
|
+
*
|
|
6
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
7
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
8
|
+
* Software Foundation, version 3 of the License.
|
|
9
|
+
*
|
|
10
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
12
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
13
|
+
* details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
16
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
export default {
|
|
19
|
+
lib: {
|
|
20
|
+
Base: {},
|
|
21
|
+
WordArray: {},
|
|
22
|
+
BufferedBlockAlgorithm: {},
|
|
23
|
+
Hasher: {},
|
|
24
|
+
Cipher: {},
|
|
25
|
+
StreamCipher: {},
|
|
26
|
+
BlockCipherMode: {},
|
|
27
|
+
BlockCipher: {},
|
|
28
|
+
CipherParams: {},
|
|
29
|
+
SerializableCipher: {},
|
|
30
|
+
PasswordBasedCipher: {}
|
|
31
|
+
},
|
|
32
|
+
x64: {
|
|
33
|
+
Word: {},
|
|
34
|
+
WordArray: {}
|
|
35
|
+
},
|
|
36
|
+
enc: {
|
|
37
|
+
Hex: {},
|
|
38
|
+
Latin1: {},
|
|
39
|
+
Utf8: {
|
|
40
|
+
parse: () => {}
|
|
41
|
+
},
|
|
42
|
+
Utf16: {},
|
|
43
|
+
Utf16BE: {},
|
|
44
|
+
Utf16LE: {},
|
|
45
|
+
Base64: {},
|
|
46
|
+
Base64url: {}
|
|
47
|
+
},
|
|
48
|
+
algo: {
|
|
49
|
+
HMAC: {},
|
|
50
|
+
MD5: {},
|
|
51
|
+
SHA1: {},
|
|
52
|
+
SHA224: {},
|
|
53
|
+
SHA256: {},
|
|
54
|
+
SHA384: {},
|
|
55
|
+
SHA512: {},
|
|
56
|
+
SHA3: {},
|
|
57
|
+
RIPEMD160: {},
|
|
58
|
+
PBKDF2: {},
|
|
59
|
+
EvpKDF: {},
|
|
60
|
+
AES: {},
|
|
61
|
+
DES: {},
|
|
62
|
+
TripleDES: {},
|
|
63
|
+
Rabbit: {},
|
|
64
|
+
RabbitLegacy: {},
|
|
65
|
+
RC4: {},
|
|
66
|
+
RC4Drop: {},
|
|
67
|
+
Blowfish: {}
|
|
68
|
+
},
|
|
69
|
+
mode: {
|
|
70
|
+
CBC: {},
|
|
71
|
+
CFB: {},
|
|
72
|
+
CTR: {},
|
|
73
|
+
CTRGladman: {},
|
|
74
|
+
ECB: {},
|
|
75
|
+
OFB: {}
|
|
76
|
+
},
|
|
77
|
+
pad: {
|
|
78
|
+
Pkcs7: {},
|
|
79
|
+
AnsiX923: {},
|
|
80
|
+
Iso10126: {},
|
|
81
|
+
Iso97971: {},
|
|
82
|
+
NoPadding: {},
|
|
83
|
+
ZeroPadding: {}
|
|
84
|
+
},
|
|
85
|
+
format: {
|
|
86
|
+
OpenSSL: {},
|
|
87
|
+
Hex: {}
|
|
88
|
+
},
|
|
89
|
+
kdf: {
|
|
90
|
+
OpenSSL: {}
|
|
91
|
+
},
|
|
92
|
+
MD5: {},
|
|
93
|
+
HmacMD5: {},
|
|
94
|
+
SHA1: {},
|
|
95
|
+
HmacSHA1: {},
|
|
96
|
+
SHA224: {},
|
|
97
|
+
HmacSHA224: {},
|
|
98
|
+
SHA256: {},
|
|
99
|
+
HmacSHA256: {},
|
|
100
|
+
SHA384: {},
|
|
101
|
+
HmacSHA384: {},
|
|
102
|
+
SHA512: {},
|
|
103
|
+
HmacSHA512: {},
|
|
104
|
+
SHA3: {},
|
|
105
|
+
HmacSHA3: {},
|
|
106
|
+
RIPEMD160: {},
|
|
107
|
+
HmacRIPEMD160: {},
|
|
108
|
+
PBKDF2: {},
|
|
109
|
+
EvpKDF: {},
|
|
110
|
+
AES: {},
|
|
111
|
+
DES: {},
|
|
112
|
+
TripleDES: {},
|
|
113
|
+
Rabbit: {},
|
|
114
|
+
RabbitLegacy: {},
|
|
115
|
+
RC4: {
|
|
116
|
+
encrypt: () => {},
|
|
117
|
+
decrypt: () => {}
|
|
118
|
+
},
|
|
119
|
+
RC4Drop: {
|
|
120
|
+
encrypt: () => {},
|
|
121
|
+
decrypt: () => {}
|
|
122
|
+
},
|
|
123
|
+
Blowfish: {}
|
|
124
|
+
};
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19
19
|
*/
|
|
20
20
|
import React from 'react';
|
|
21
|
-
import { Flex } from '@instructure/ui-flex';
|
|
22
21
|
import { Heading } from '@instructure/ui-heading';
|
|
23
22
|
import { CloseButton } from '@instructure/ui-buttons';
|
|
24
23
|
import { View } from '@instructure/ui-view';
|
|
@@ -33,12 +32,12 @@ export function ExternalToolDialogModal(props) {
|
|
|
33
32
|
onOpen: props.onOpen,
|
|
34
33
|
onClose: props.onClose,
|
|
35
34
|
mountNode: props.mountNode
|
|
36
|
-
}, /*#__PURE__*/React.createElement(Modal.Header, null, /*#__PURE__*/React.createElement(
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
}, /*#__PURE__*/React.createElement(Modal.Header, null, /*#__PURE__*/React.createElement(Heading, null, props.name), /*#__PURE__*/React.createElement(CloseButton, {
|
|
36
|
+
placement: "end",
|
|
37
|
+
offset: "medium",
|
|
39
38
|
onClick: props.onCloseButton,
|
|
40
39
|
screenReaderLabel: formatMessage('Close')
|
|
41
|
-
}))
|
|
40
|
+
})), /*#__PURE__*/React.createElement(Modal.Body, {
|
|
42
41
|
padding: "0"
|
|
43
42
|
}, /*#__PURE__*/React.createElement(View, {
|
|
44
43
|
as: "div",
|