@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.
Files changed (43) hide show
  1. package/.mocharc.js +7 -0
  2. package/CHANGELOG.md +20 -0
  3. package/es/enhance-user-content/mathml.js +8 -5
  4. package/es/rce/RCEWrapper.js +65 -6
  5. package/es/rce/RCEWrapperProps.js +1 -0
  6. package/es/rce/__mocks__/_mockCryptoEs.js +124 -0
  7. package/es/rce/plugins/instructure_equation/EquationEditorModal/parseLatex.js +0 -2
  8. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +4 -5
  9. package/es/rce/plugins/shared/CanvasContentTray.js +8 -8
  10. package/es/rce/plugins/shared/ContentSelection.js +7 -3
  11. package/es/rce/plugins/shared/ImageCropper/Preview.js +8 -7
  12. package/es/rce/plugins/shared/LinkDisplay.js +2 -2
  13. package/es/rce/plugins/tinymce-a11y-checker/rules/large-text-contrast.js +9 -0
  14. package/es/rce/plugins/tinymce-a11y-checker/rules/small-text-contrast.js +9 -0
  15. package/es/translations/locales/da-x-k12.js +39 -0
  16. package/es/translations/locales/de.js +4 -4
  17. package/es/translations/locales/fi.js +39 -0
  18. package/es/translations/locales/nb-x-k12.js +39 -0
  19. package/es/translations/locales/sv-x-k12.js +39 -0
  20. package/es/util/encrypted-storage.js +84 -0
  21. package/jest/jest-setup.js +5 -3
  22. package/jest.config.js +1 -0
  23. package/lib/enhance-user-content/mathml.js +8 -5
  24. package/lib/rce/RCEWrapper.js +65 -6
  25. package/lib/rce/RCEWrapperProps.js +1 -0
  26. package/lib/rce/__mocks__/_mockCryptoEs.js +124 -0
  27. package/lib/rce/plugins/instructure_equation/EquationEditorModal/parseLatex.js +0 -2
  28. package/lib/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +4 -5
  29. package/lib/rce/plugins/shared/CanvasContentTray.js +8 -8
  30. package/lib/rce/plugins/shared/ContentSelection.js +7 -3
  31. package/lib/rce/plugins/shared/ImageCropper/Preview.js +8 -7
  32. package/lib/rce/plugins/shared/LinkDisplay.js +2 -2
  33. package/lib/rce/plugins/tinymce-a11y-checker/rules/large-text-contrast.js +9 -0
  34. package/lib/rce/plugins/tinymce-a11y-checker/rules/small-text-contrast.js +9 -0
  35. package/lib/translations/locales/da-x-k12.js +39 -0
  36. package/lib/translations/locales/de.js +4 -4
  37. package/lib/translations/locales/fi.js +39 -0
  38. package/lib/translations/locales/nb-x-k12.js +39 -0
  39. package/lib/translations/locales/sv-x-k12.js +39 -0
  40. package/lib/util/encrypted-storage.js +84 -0
  41. package/package.json +5 -5
  42. package/es/rce/getBrowser.js +0 -53
  43. 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
+ }
@@ -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
- $(message[1]).find('.hidden-readable [class^="MathJax"], .hidden-readable [id^="MathJax"]').remove();
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) {
@@ -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
- this.storage = window.localStorage;
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, JSON.stringify({
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 && JSON.parse(this.storage.getItem(key));
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;
@@ -125,5 +125,6 @@ export const rceWrapperPropTypes = {
125
125
  features: PropTypes.objectOf(PropTypes.bool),
126
126
  flashAlertTimeout: PropTypes.number,
127
127
  timezone: PropTypes.string,
128
+ userCacheKey: PropTypes.string,
128
129
  externalToolsConfig: externalToolsConfigPropType
129
130
  };
@@ -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
+ };
@@ -68,8 +68,6 @@ export const parseLatex = editor => {
68
68
  };
69
69
  } catch (ex) {
70
70
  // probably failed to create the new URL
71
- // eslint-disable-next-line no-console
72
- console.error(ex);
73
71
  return {};
74
72
  }
75
73
  } else if (wholeText) {
@@ -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(Flex, null, /*#__PURE__*/React.createElement(Flex.Item, {
37
- grow: true
38
- }, /*#__PURE__*/React.createElement(Heading, null, props.name)), /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(CloseButton, {
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
- })))), /*#__PURE__*/React.createElement(Modal.Body, {
40
+ })), /*#__PURE__*/React.createElement(Modal.Body, {
42
41
  padding: "0"
43
42
  }, /*#__PURE__*/React.createElement(View, {
44
43
  as: "div",