@instructure/canvas-rce 7.3.0 → 8.0.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 (162) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/{es/rce/plugins/shared/ai_tools/index.js → __mocks__/@instructure/ui-media-player/_mockUiMediaPlayer.js} +4 -4
  3. package/__tests__/common/mimeClass.test.js +25 -1
  4. package/__tests__/rcs/api.test.js +280 -251
  5. package/es/canvasFileBrowser/FileBrowser.d.ts +2 -2
  6. package/es/canvasFileBrowser/FileBrowser.js +8 -7
  7. package/es/common/mimeClass.js +3 -1
  8. package/es/defaultTinymceConfig.js +47 -49
  9. package/es/enhance-user-content/doc_previews.js +5 -0
  10. package/es/enhance-user-content/enhance_user_content.js +6 -8
  11. package/es/enhance-user-content/index.d.ts +3 -1
  12. package/es/enhance-user-content/index.js +3 -1
  13. package/es/enhance-user-content/instructure_helper.js +1 -0
  14. package/es/enhance-user-content/youtube_overlay.js +18 -0
  15. package/es/getThemeVars.d.ts +1 -1
  16. package/es/getThemeVars.js +23 -26
  17. package/es/rce/AlertMessageArea.d.ts +2 -2
  18. package/es/rce/AlertMessageArea.js +3 -3
  19. package/es/rce/KeyboardShortcutModal.js +2 -2
  20. package/es/rce/RCE.d.ts +9 -0
  21. package/es/rce/RCE.js +4 -0
  22. package/es/rce/RCEGlobals.d.ts +2 -0
  23. package/es/rce/RCEGlobals.js +1 -0
  24. package/es/rce/RCEVariants.d.ts +1 -2
  25. package/es/rce/RCEVariants.js +1 -2
  26. package/es/rce/RCEWrapper.d.ts +16 -26
  27. package/es/rce/RCEWrapper.js +227 -271
  28. package/es/rce/RCEWrapper.utils.d.ts +1 -1
  29. package/es/rce/RCEWrapperProps.d.ts +2 -1
  30. package/es/rce/RCEWrapperProps.js +2 -1
  31. package/es/rce/StatusBar.d.ts +0 -1
  32. package/es/rce/StatusBar.js +3 -28
  33. package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.d.ts +2 -1
  34. package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.js +3 -1
  35. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.d.ts +1 -0
  36. package/es/rce/plugins/instructure_equation/EquationEditorModal/index.js +12 -2
  37. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageOptions.js +2 -2
  38. package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageSection.js +3 -3
  39. package/es/rce/plugins/instructure_icon_maker/svg/constants.d.ts +20 -5
  40. package/es/rce/plugins/instructure_icon_maker/svg/utils.d.ts +1 -1
  41. package/es/rce/plugins/instructure_icon_maker/utils/IconMakerFormHasChanges.js +2 -2
  42. package/es/rce/plugins/instructure_image/ImageEmbedOptions.d.ts +0 -2
  43. package/es/rce/plugins/instructure_image/ImageEmbedOptions.js +2 -9
  44. package/es/rce/plugins/instructure_paste/plugin.js +18 -12
  45. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.d.ts +1 -1
  46. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog.d.ts +1 -1
  47. package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog.js +25 -25
  48. package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.d.ts +4 -0
  49. package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.js +4 -0
  50. package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.d.ts +11 -2
  51. package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.js +92 -10
  52. package/es/rce/plugins/instructure_record/AudioOptionsTray/index.d.ts +13 -1
  53. package/es/rce/plugins/instructure_record/AudioOptionsTray/index.js +216 -24
  54. package/es/rce/plugins/instructure_record/MediaPanel/index.js +16 -5
  55. package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.d.ts +14 -13
  56. package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +110 -39
  57. package/es/rce/plugins/instructure_record/VideoOptionsTray/index.d.ts +11 -1
  58. package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +242 -67
  59. package/es/rce/plugins/instructure_record/clickCallback.js +19 -4
  60. package/es/rce/plugins/instructure_record/mediaTranslations.js +1 -1
  61. package/es/rce/plugins/instructure_record/playerLayoutOptions.d.ts +25 -0
  62. package/es/rce/plugins/instructure_record/playerLayoutOptions.js +91 -0
  63. package/es/rce/plugins/instructure_record/plugin.js +2 -5
  64. package/es/rce/plugins/instructure_record/utils.d.ts +3 -0
  65. package/es/rce/plugins/instructure_record/utils.js +31 -0
  66. package/es/rce/plugins/instructure_studio_media_options/plugin.js +82 -24
  67. package/es/rce/plugins/instructure_wordcount/components/WordCountModal.js +1 -0
  68. package/es/rce/plugins/shared/ContentSelection.d.ts +6 -1
  69. package/es/rce/plugins/shared/ContentSelection.js +15 -6
  70. package/es/rce/plugins/shared/DimensionsInput/DimensionInput.js +1 -2
  71. package/es/rce/plugins/shared/DimensionsInput/index.js +11 -12
  72. package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.d.ts +1 -1
  73. package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.js +4 -3
  74. package/es/rce/plugins/shared/StudioLtiSupportUtils.d.ts +27 -5
  75. package/es/rce/plugins/shared/StudioLtiSupportUtils.js +94 -9
  76. package/es/rce/plugins/shared/Upload/UploadFile.js +1 -8
  77. package/es/rce/style.d.ts +2 -1
  78. package/es/rce/style.js +4 -2
  79. package/es/rcs/api.d.ts +5 -10
  80. package/es/rcs/api.js +15 -21
  81. package/es/rcs/fake.d.ts +1 -7
  82. package/es/rcs/fake.js +1 -47
  83. package/es/sidebar/actions/media.d.ts +19 -6
  84. package/es/sidebar/actions/media.js +17 -4
  85. package/es/sidebar/actions/upload.d.ts +3 -3
  86. package/es/sidebar/actions/upload.js +9 -9
  87. package/es/sidebar/containers/Sidebar.js +0 -2
  88. package/es/sidebar/containers/sidebarHandlers.d.ts +2 -4
  89. package/es/sidebar/containers/sidebarHandlers.js +2 -5
  90. package/es/sidebar/reducers/index.d.ts +0 -1
  91. package/es/sidebar/reducers/index.js +0 -2
  92. package/es/sidebar/store/initialState.d.ts +0 -1
  93. package/es/sidebar/store/initialState.js +0 -5
  94. package/es/translations/locales/ar.js +77 -77
  95. package/es/translations/locales/ca.js +77 -77
  96. package/es/translations/locales/cy.js +77 -77
  97. package/es/translations/locales/da-x-k12.js +77 -77
  98. package/es/translations/locales/da.js +77 -77
  99. package/es/translations/locales/de.js +77 -77
  100. package/es/translations/locales/el.js +0 -9
  101. package/es/translations/locales/en-AU-x-unimelb.js +77 -77
  102. package/es/translations/locales/en-GB-x-ukhe.js +77 -77
  103. package/es/translations/locales/en.js +67 -79
  104. package/es/translations/locales/en_AU.js +77 -77
  105. package/es/translations/locales/en_CA.js +77 -77
  106. package/es/translations/locales/en_CY.js +77 -77
  107. package/es/translations/locales/en_GB.js +77 -77
  108. package/es/translations/locales/es.js +77 -77
  109. package/es/translations/locales/es_ES.js +77 -77
  110. package/es/translations/locales/fa_IR.js +0 -9
  111. package/es/translations/locales/fi.js +77 -77
  112. package/es/translations/locales/fr.js +77 -77
  113. package/es/translations/locales/fr_CA.js +77 -77
  114. package/es/translations/locales/ga.js +77 -77
  115. package/es/translations/locales/he.js +0 -9
  116. package/es/translations/locales/hi.js +77 -77
  117. package/es/translations/locales/ht.js +77 -77
  118. package/es/translations/locales/hu.js +0 -36
  119. package/es/translations/locales/hy.js +0 -9
  120. package/es/translations/locales/id.js +77 -77
  121. package/es/translations/locales/is.js +77 -77
  122. package/es/translations/locales/it.js +77 -77
  123. package/es/translations/locales/ja.js +77 -77
  124. package/es/translations/locales/ko.js +2455 -133
  125. package/es/translations/locales/mi.js +77 -77
  126. package/es/translations/locales/ms.js +77 -77
  127. package/es/translations/locales/nb-x-k12.js +77 -77
  128. package/es/translations/locales/nb.js +77 -77
  129. package/es/translations/locales/nl.js +78 -78
  130. package/es/translations/locales/nn.js +0 -36
  131. package/es/translations/locales/pl.js +77 -77
  132. package/es/translations/locales/pt.js +77 -77
  133. package/es/translations/locales/pt_BR.js +77 -77
  134. package/es/translations/locales/ru.js +77 -77
  135. package/es/translations/locales/sl.js +77 -77
  136. package/es/translations/locales/sv-x-k12.js +77 -77
  137. package/es/translations/locales/sv.js +77 -77
  138. package/es/translations/locales/th.js +77 -77
  139. package/es/translations/locales/tr.js +1962 -18
  140. package/es/translations/locales/uk_UA.js +0 -9
  141. package/es/translations/locales/vi.js +77 -77
  142. package/es/translations/locales/zh-Hans.js +77 -77
  143. package/es/translations/locales/zh-Hant.js +77 -77
  144. package/es/translations/locales/zh.js +77 -77
  145. package/es/translations/locales/zh_HK.js +77 -77
  146. package/eslint.config.js +16 -147
  147. package/jest/jest-setup.js +1 -0
  148. package/jest.config.js +2 -0
  149. package/oxlint.json +84 -0
  150. package/package.json +86 -62
  151. package/tsconfig.json +3 -2
  152. package/es/rce/plugins/shared/ai_tools/AIResponseModal.d.ts +0 -10
  153. package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +0 -67
  154. package/es/rce/plugins/shared/ai_tools/AIToolsTray.d.ts +0 -18
  155. package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +0 -489
  156. package/es/rce/plugins/shared/ai_tools/aiicons.d.ts +0 -7
  157. package/es/rce/plugins/shared/ai_tools/aiicons.js +0 -60
  158. package/es/rce/plugins/shared/ai_tools/index.d.ts +0 -3
  159. package/es/sidebar/actions/flickr.d.ts +0 -20
  160. package/es/sidebar/actions/flickr.js +0 -60
  161. package/es/sidebar/reducers/flickr.d.ts +0 -1
  162. package/es/sidebar/reducers/flickr.js +0 -49
@@ -17,63 +17,63 @@ import _pt from "prop-types";
17
17
  * with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
  */
19
19
 
20
- import React, { Suspense } from "react";
21
- import { Editor } from "@tinymce/tinymce-react";
22
- import tinymce from "tinymce";
23
- import _ from "lodash";
24
- import { StoreProvider } from "./plugins/shared/StoreContext";
25
- import { IconKeyboardShortcutsLine } from "@instructure/ui-icons";
26
- import { Alert } from "@instructure/ui-alerts";
27
- import { Spinner } from "@instructure/ui-spinner";
28
- import { View } from "@instructure/ui-view";
29
- import { debounce } from "@instructure/debounce";
30
- import { uid } from "@instructure/uid";
31
- import { FocusRegionManager } from "@instructure/ui-a11y-utils";
32
- import getCookie from "../common/getCookie";
33
- import formatMessage from "../format-message";
34
- import * as contentInsertion from "./contentInsertion";
35
- import indicatorRegion from "./indicatorRegion";
36
- import { editorLanguage } from "./editorLanguage";
37
- import normalizeLocale from "./normalizeLocale";
38
- import { sanitizePlugins } from "./sanitizePlugins";
39
- import RCEGlobals from "./RCEGlobals";
40
- import defaultTinymceConfig from "../defaultTinymceConfig";
41
- import { FS_CHANGEEVENT, FS_ELEMENT, FS_ENABLED, FS_EXIT, FS_REQUEST, instuiPopupMountNodeFn } from "../util/fullscreenHelpers";
42
- import indicate from "../common/indicate";
43
- import bridge from "../bridge";
44
- import CanvasContentTray from "./plugins/shared/CanvasContentTray";
45
- import StatusBar, { PRETTY_HTML_EDITOR_VIEW, RAW_HTML_EDITOR_VIEW, WYSIWYG_VIEW } from "./StatusBar";
46
- import { VIEW_CHANGE } from "./customEvents";
47
- import ShowOnFocusButton from "./ShowOnFocusButton";
48
- import KeyboardShortcutModal from "./KeyboardShortcutModal";
49
- import AlertMessageArea from "./AlertMessageArea";
50
- import alertHandler from "./alertHandler";
51
- import { isFileLink, isImageEmbed } from "./plugins/shared/ContentSelection";
52
- import { countShouldIgnore } from "./plugins/instructure_wordcount/utils/countContent";
53
- import launchWordcountModal from "./plugins/instructure_wordcount/clickCallback";
54
- import { determineOSDependentKey } from "./userOS";
55
- import skinCSS from "./tinymce.oxide.skin.min.css";
56
- import contentCSS from "./tinymce.oxide.content.min.css";
57
- import { rceWrapperPropTypes } from "./RCEWrapperProps";
58
- import { insertPlaceholder, placeholderInfoFor, removePlaceholder } from "../util/loadingPlaceholder";
59
- import { transformRceContentForEditing } from "./transformContent";
20
+ import React, { Suspense } from 'react';
21
+ import { Editor } from '@tinymce/tinymce-react';
22
+ import tinymce from 'tinymce';
23
+ import { uniqBy } from 'es-toolkit/compat';
24
+ import { StoreProvider } from './plugins/shared/StoreContext';
25
+ import { IconKeyboardShortcutsLine } from '@instructure/ui-icons';
26
+ import { Alert } from '@instructure/ui-alerts';
27
+ import { Spinner } from '@instructure/ui-spinner';
28
+ import { View } from '@instructure/ui-view';
29
+ import { debounce } from '@instructure/debounce';
30
+ import { uid } from '@instructure/uid';
31
+ import { FocusRegionManager } from '@instructure/ui-a11y-utils';
32
+ import getCookie from '../common/getCookie';
33
+ import formatMessage from '../format-message';
34
+ import * as contentInsertion from './contentInsertion';
35
+ import indicatorRegion from './indicatorRegion';
36
+ import { editorLanguage } from './editorLanguage';
37
+ import normalizeLocale from './normalizeLocale';
38
+ import { sanitizePlugins } from './sanitizePlugins';
39
+ import RCEGlobals from './RCEGlobals';
40
+ import defaultTinymceConfig from '../defaultTinymceConfig';
41
+ import { FS_CHANGEEVENT, FS_ELEMENT, FS_ENABLED, FS_EXIT, FS_REQUEST, instuiPopupMountNodeFn } from '../util/fullscreenHelpers';
42
+ import indicate from '../common/indicate';
43
+ import bridge from '../bridge';
44
+ import CanvasContentTray from './plugins/shared/CanvasContentTray';
45
+ import StatusBar, { PRETTY_HTML_EDITOR_VIEW, RAW_HTML_EDITOR_VIEW, WYSIWYG_VIEW } from './StatusBar';
46
+ import { VIEW_CHANGE } from './customEvents';
47
+ import ShowOnFocusButton from './ShowOnFocusButton';
48
+ import KeyboardShortcutModal from './KeyboardShortcutModal';
49
+ import AlertMessageArea from './AlertMessageArea';
50
+ import alertHandler from './alertHandler';
51
+ import { isFileLink, isImageEmbed } from './plugins/shared/ContentSelection';
52
+ import { countShouldIgnore } from './plugins/instructure_wordcount/utils/countContent';
53
+ import launchWordcountModal from './plugins/instructure_wordcount/clickCallback';
54
+ import { determineOSDependentKey } from './userOS';
55
+ import skinCSS from './tinymce.oxide.skin.min.css';
56
+ import contentCSS from './tinymce.oxide.content.min.css';
57
+ import { rceWrapperPropTypes } from './RCEWrapperProps';
58
+ import { insertPlaceholder, placeholderInfoFor, removePlaceholder } from '../util/loadingPlaceholder';
59
+ import { transformRceContentForEditing } from './transformContent';
60
60
  // @ts-expect-error
61
- import { IconMoreSolid } from "@instructure/ui-icons/es/svg";
62
- import EncryptedStorage from "../util/encrypted-storage";
63
- import buildStyle from "./style";
64
- import { getMenubarForVariant, getMenuForVariant, getToolbarForVariant, getStatusBarFeaturesForVariant } from "./RCEVariants";
65
- import { focusFirstMenuButton, focusToolbar, isElementWithinTable, mergeMenu, mergeMenuItems, mergePlugins, mergeToolbar, parsePluginsToExclude, patchAutosavedContent } from "./RCEWrapper.utils";
66
- import { externalToolsForToolbar } from "./plugins/instructure_rce_external_tools/util/externalToolsForToolbar";
67
- import { initScreenreaderOnFormat } from "./screenreaderOnFormat";
68
- import { normalizeContainingContext } from "../util/contextHelper";
69
- const RestoreAutoSaveModal = /*#__PURE__*/React.lazy(() => import("./RestoreAutoSaveModal"));
70
- const RceHtmlEditor = /*#__PURE__*/React.lazy(() => import("./RceHtmlEditor"));
61
+ import { IconMoreSolid } from '@instructure/ui-icons/es/svg';
62
+ import EncryptedStorage from '../util/encrypted-storage';
63
+ import buildStyle from './style';
64
+ import { getMenubarForVariant, getMenuForVariant, getToolbarForVariant, getStatusBarFeaturesForVariant } from './RCEVariants';
65
+ import { focusFirstMenuButton, focusToolbar, isElementWithinTable, mergeMenu, mergeMenuItems, mergePlugins, mergeToolbar, parsePluginsToExclude, patchAutosavedContent } from './RCEWrapper.utils';
66
+ import { externalToolsForToolbar } from './plugins/instructure_rce_external_tools/util/externalToolsForToolbar';
67
+ import { initScreenreaderOnFormat } from './screenreaderOnFormat';
68
+ import { normalizeContainingContext } from '../util/contextHelper';
69
+ const RestoreAutoSaveModal = /*#__PURE__*/React.lazy(() => import('./RestoreAutoSaveModal'));
70
+ const RceHtmlEditor = /*#__PURE__*/React.lazy(() => import('./RceHtmlEditor'));
71
71
  const ASYNC_FOCUS_TIMEOUT = 250;
72
- const DEFAULT_RCE_HEIGHT = "400px";
72
+ const DEFAULT_RCE_HEIGHT = '400px';
73
73
  function addKebabIcon(editor) {
74
74
  // This has to be done here instead of of in plugins/instructure-ui-icons/plugin.ts
75
75
  // presumably because the toolbar gets created before that plugin is loaded?
76
- editor.ui.registry.addIcon("more-drawer", IconMoreSolid.src);
76
+ editor.ui.registry.addIcon('more-drawer', IconMoreSolid.src);
77
77
  }
78
78
 
79
79
  // Get oxide the default skin injected into the DOM before the overrides loaded by themeable
@@ -81,8 +81,8 @@ let inserted = false;
81
81
  function injectTinySkin() {
82
82
  if (inserted) return;
83
83
  inserted = true;
84
- const style = document.createElement("style");
85
- style.setAttribute("data-skin", "tiny oxide skin");
84
+ const style = document.createElement('style');
85
+ style.setAttribute('data-skin', 'tiny oxide skin');
86
86
  style.appendChild(document.createTextNode(skinCSS));
87
87
  // there's CSS from discussions that turns the instui Selectors bold
88
88
  // and in classic quizzes that also mucks with padding
@@ -90,9 +90,9 @@ function injectTinySkin() {
90
90
  #discussion-edit-view .rce-wrapper input[readonly] {font-weight: normal;}
91
91
  #quiz_edit_wrapper .rce-wrapper input[readonly] {font-weight: normal; padding-left: .75rem;}
92
92
  `));
93
- const beforeMe = document.head.querySelector("style[data-glamor]") ||
93
+ const beforeMe = document.head.querySelector('style[data-glamor]') ||
94
94
  // find instui's themeable stylesheet
95
- document.head.querySelector("style") ||
95
+ document.head.querySelector('style') ||
96
96
  // find any stylesheet
97
97
  document.head.firstElementChild;
98
98
  document.head.insertBefore(style, beforeMe);
@@ -105,7 +105,7 @@ export function storageAvailable() {
105
105
  let storage = null;
106
106
  try {
107
107
  storage = window.localStorage;
108
- const x = "__storage_test__";
108
+ const x = '__storage_test__';
109
109
  storage.setItem(x, x);
110
110
  storage.removeItem(x);
111
111
  return true;
@@ -117,15 +117,15 @@ export function storageAvailable() {
117
117
  e.code === 1014 ||
118
118
  // test name field too, because code might not be present
119
119
  // everything except Firefox
120
- e.name === "QuotaExceededError" ||
120
+ e.name === 'QuotaExceededError' ||
121
121
  // Firefox
122
- e.name === "NS_ERROR_DOM_QUOTA_REACHED") &&
122
+ e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
123
123
  // acknowledge QuotaExceededError only if there's something already stored
124
124
  storage && storage.length !== 0;
125
125
  }
126
126
  }
127
127
  function renderLoading() {
128
- return formatMessage("Loading");
128
+ return formatMessage('Loading');
129
129
  }
130
130
  let alertIdValue = 0;
131
131
  class RCEWrapper extends React.Component {
@@ -144,7 +144,6 @@ class RCEWrapper extends React.Component {
144
144
  this._statusBarId = void 0;
145
145
  this._textareaEl = void 0;
146
146
  this._effectiveContainingContext = void 0;
147
- this.AIToolsTray = void 0;
148
147
  this.editor = void 0;
149
148
  this.initialContent = void 0;
150
149
  this.intersectionObserver = void 0;
@@ -199,7 +198,7 @@ class RCEWrapper extends React.Component {
199
198
  this.setState(newState);
200
199
  this.checkAccessibility();
201
200
  if (newView === PRETTY_HTML_EDITOR_VIEW || newView === RAW_HTML_EDITOR_VIEW) {
202
- this.storage?.setItem?.("rce.htmleditor", newView);
201
+ this.storage?.setItem?.('rce.htmleditor', newView);
203
202
  }
204
203
 
205
204
  // Emit view change event
@@ -216,7 +215,7 @@ class RCEWrapper extends React.Component {
216
215
  if (document[FS_ELEMENT]) {
217
216
  // @ts-expect-error
218
217
  this.resizeObserver.observe(document[FS_ELEMENT]);
219
- window.visualViewport?.addEventListener("resize", this._handleFullscreenResize);
218
+ window.visualViewport?.addEventListener('resize', this._handleFullscreenResize);
220
219
  this._handleFullscreenResize();
221
220
  // @ts-expect-error
222
221
  this._focusRegion = FocusRegionManager.activateRegion(
@@ -227,7 +226,7 @@ class RCEWrapper extends React.Component {
227
226
  } else {
228
227
  event.target.removeEventListener(FS_CHANGEEVENT, this._onFullscreenChange);
229
228
  this.resizeObserver.unobserve(event.target);
230
- window.visualViewport?.removeEventListener("resize", this._handleFullscreenResize);
229
+ window.visualViewport?.removeEventListener('resize', this._handleFullscreenResize);
231
230
  this._setHeight(this.state.fullscreenState.prevHeight);
232
231
  if (this._focusRegion) {
233
232
  FocusRegionManager.blurRegion(event.target, this._focusRegion.id);
@@ -260,35 +259,35 @@ class RCEWrapper extends React.Component {
260
259
  // what we've got for now.
261
260
  const ifr = this.iframe;
262
261
  if (ifr?.parentElement) {
263
- ifr.parentElement.classList.add("active");
262
+ ifr.parentElement.classList.add('active');
264
263
  }
265
264
  this.handleFocus();
266
265
  };
267
266
  this.handleBlurEditor = event => {
268
267
  const ifr = this.iframe;
269
268
  if (ifr?.parentElement) {
270
- ifr.parentElement.classList.remove("active");
269
+ ifr.parentElement.classList.remove('active');
271
270
  }
272
271
  this.handleBlur(event);
273
272
  };
274
273
  this.handleKey = event => {
275
- if (event.code === "F9" && event.altKey) {
274
+ if (event.code === 'F9' && event.altKey) {
276
275
  event.preventDefault();
277
276
  event.stopPropagation();
278
277
  // @ts-expect-error
279
278
  focusFirstMenuButton(this._elementRef.current);
280
- } else if (event.code === "F10" && event.altKey) {
279
+ } else if (event.code === 'F10' && event.altKey) {
281
280
  event.preventDefault();
282
281
  event.stopPropagation();
283
282
  // @ts-expect-error
284
283
  focusToolbar(this._elementRef.current);
285
- } else if (event.code === "F8" && event.altKey) {
284
+ } else if (event.code === 'F8' && event.altKey) {
286
285
  event.preventDefault();
287
286
  event.stopPropagation();
288
287
  this.openKBShortcutModal();
289
- } else if (event.code === "Escape") {
288
+ } else if (event.code === 'Escape') {
290
289
  bridge.hideTrays();
291
- } else if (["n", "N", "d", "D"].indexOf(event.key) !== -1) {
290
+ } else if (['n', 'N', 'd', 'D'].indexOf(event.key) !== -1) {
292
291
  // Prevent key events from bubbling up on touch screen device
293
292
  event.stopPropagation();
294
293
  }
@@ -317,32 +316,64 @@ class RCEWrapper extends React.Component {
317
316
  // @ts-expect-error
318
317
  textarea.value = this.getCode();
319
318
  textarea.style.height = this.state.height;
320
- textarea.removeAttribute("aria-hidden");
321
- if (document.body.classList.contains("Underline-All-Links__enabled")) {
319
+ textarea.removeAttribute('aria-hidden');
320
+ if (document.body.classList.contains('Underline-All-Links__enabled')) {
322
321
  if (this.iframe?.contentDocument) {
323
- this.iframe.contentDocument.body.classList.add("Underline-All-Links__enabled");
322
+ this.iframe.contentDocument.body.classList.add('Underline-All-Links__enabled');
324
323
  }
325
324
  }
326
- editor.on("wordCountUpdate", this.onWordCountUpdate);
325
+ editor.on('wordCountUpdate', this.onWordCountUpdate);
327
326
  // add an aria-label to the application div that wraps RCE
328
327
  // and change role from "application" to "document" to ensure
329
328
  // the editor gets properly picked up by screen readers
330
329
  const tinyapp = document.querySelector('.tox-tinymce[role="application"]');
331
330
  if (tinyapp) {
332
- tinyapp.setAttribute("aria-label", formatMessage("Rich Content Editor"));
333
- tinyapp.setAttribute("role", "document");
334
- tinyapp.setAttribute("tabIndex", "-1");
331
+ tinyapp.setAttribute('aria-label', formatMessage('Rich Content Editor'));
332
+ tinyapp.setAttribute('role', 'document');
333
+ tinyapp.setAttribute('tabIndex', '-1');
334
+
335
+ // tinyMCE browser detection is wrong for Edge tinymce.Env.browser.isEdge
336
+ const isEdge = /edg/i.test(navigator.userAgent);
337
+ if (isEdge) {
338
+ // Edge translation service breaks the editor
339
+ tinyapp.setAttribute('translate', 'no');
340
+ }
341
+ }
342
+
343
+ // remove role="aplication" attribute from the iframe body
344
+ // tinymce adds this when the editor is wrapped in an iframe
345
+ // which makes RCE input fields inaccessible to screen readers
346
+ const iframe = tinyapp?.querySelector('iframe');
347
+ const body = iframe?.contentDocument?.body;
348
+ if (body) {
349
+ const observer = new MutationObserver(() => {
350
+ try {
351
+ if (body && body.getAttribute('role') === 'application') {
352
+ body.removeAttribute('role');
353
+ }
354
+ } catch (_) {
355
+ /* pass */
356
+ }
357
+ });
358
+ observer.observe(body, {
359
+ attributes: true,
360
+ childList: false,
361
+ subtree: false
362
+ });
363
+ body.setAttribute('data-role-checked', 'true'); // to trigger observer
364
+
365
+ setTimeout(() => observer.disconnect(), 10000);
335
366
  }
336
367
 
337
368
  // Probably should do this in tinymce.scss, but we only want it in new rce
338
- textarea.style.resize = "none";
339
- editor.on("keydown", this.handleKey);
340
- editor.on("FullscreenStateChanged", this._onFullscreenChange);
369
+ textarea.style.resize = 'none';
370
+ editor.on('keydown', this.handleKey);
371
+ editor.on('FullscreenStateChanged', this._onFullscreenChange);
341
372
  // This propagates click events on the editor out of the iframe to the parent
342
373
  // document. We need this so that click events get captured properly by instui
343
374
  // focus-trapping components, so they properly ignore trapping focus on click.
344
- editor.on("click", () => window.document.body.click(), true);
345
- editor.on("Cut Change input Undo Redo", debounce(this.handleInputChange, 1000));
375
+ editor.on('click', () => window.document.body.click(), true);
376
+ editor.on('Cut Change input Undo Redo', debounce(this.handleInputChange, 1000));
346
377
  initScreenreaderOnFormat(editor);
347
378
  this.announceContextToolbars(editor);
348
379
  if (this.isAutoSaving) {
@@ -354,12 +385,12 @@ class RCEWrapper extends React.Component {
354
385
 
355
386
  // readonly should have been handled via the init property passed
356
387
  // to <Editor>, but it's not.
357
- editor.mode.set(this.props.readOnly ? "readonly" : "design");
388
+ editor.mode.set(this.props.readOnly ? 'readonly' : 'design');
358
389
 
359
390
  // Not using iframe_aria_text because compatibility issues.
360
391
  // Not using iframe_attrs because library overwriting.
361
392
  if (this.iframe) {
362
- this.iframe.setAttribute("title", formatMessage("Rich Text Area. Press {OSKey}+F8 for Rich Content Editor shortcuts.", {
393
+ this.iframe.setAttribute('title', formatMessage('Rich Text Area. Press {OSKey}+F8 for Rich Content Editor shortcuts.', {
363
394
  OSKey: determineOSDependentKey()
364
395
  }));
365
396
  }
@@ -372,8 +403,8 @@ class RCEWrapper extends React.Component {
372
403
 
373
404
  // cleans up highlight artifacts from findreplace plugin
374
405
  if (this.getRequiredFeatureStatuses().rce_find_replace) {
375
- editor.on("undo redo", _e => {
376
- if (editor?.dom?.doc?.getElementsByClassName?.("mce-match-marker")?.length > 0) {
406
+ editor.on('undo redo', _e => {
407
+ if (editor?.dom?.doc?.getElementsByClassName?.('mce-match-marker')?.length > 0) {
377
408
  editor.plugins?.searchreplace?.done();
378
409
  }
379
410
  });
@@ -392,7 +423,7 @@ class RCEWrapper extends React.Component {
392
423
  // This workaround removes attribute, thusly causing navigation to work correctly again.
393
424
  // For the correct solution, Keying.config should have { selector: '.tox-toolbar__group' }
394
425
  // in https://github.com/tinymce/tinymce/blob/develop/modules/alloy/src/main/ts/ephox/alloy/ui/schema/SplitSlidingToolbarSchema.ts
395
- this._elementRef.current?.querySelectorAll(".tox-toolbar-overlord button[data-alloy-tabstop]").forEach(it => it.removeAttribute("data-alloy-tabstop"));
426
+ this._elementRef.current?.querySelectorAll('.tox-toolbar-overlord button[data-alloy-tabstop]').forEach(it => it.removeAttribute('data-alloy-tabstop'));
396
427
  };
397
428
  /**
398
429
  * Sets up selection saving and restoration logic.
@@ -419,7 +450,7 @@ class RCEWrapper extends React.Component {
419
450
  selectionWasReset = false;
420
451
  }
421
452
  };
422
- editor.on("blur", () => {
453
+ editor.on('blur', () => {
423
454
  editorHasFocus = false;
424
455
  selectionWasReset = false;
425
456
  if (!this.editor) return;
@@ -428,7 +459,7 @@ class RCEWrapper extends React.Component {
428
459
  isForward: this.editor.selection.isForward()
429
460
  };
430
461
  });
431
- editor.on("focus", () => {
462
+ editor.on('focus', () => {
432
463
  // We need to restore the selection when the editor regains focus because sometimes the editor regains
433
464
  // focus without the user setting the selection themselves (such as when they interact with the toolbar)
434
465
  // and if we didn't, we would end up saving the reset selection before a user managed to actually insert
@@ -437,7 +468,7 @@ class RCEWrapper extends React.Component {
437
468
  editorHasFocus = true;
438
469
  selectionWasReset = false;
439
470
  });
440
- editor.on("SelectionChange", () => {
471
+ editor.on('SelectionChange', () => {
441
472
  if (editorHasFocus) {
442
473
  // We don't care if a selection reset occurs when the editor has focus, the user probably intended that
443
474
  // At least they will see the effect
@@ -447,14 +478,14 @@ class RCEWrapper extends React.Component {
447
478
  const selection = this.editor.selection.normalize();
448
479
 
449
480
  // Detect a browser-reset selection (e.g. From invoking the Find command)
450
- if (selection.startContainer?.nodeName === "BODY" && selection.startContainer === selection.endContainer && selection.startOffset === 0 && selection.endOffset === 0) {
481
+ if (selection.startContainer?.nodeName === 'BODY' && selection.startContainer === selection.endContainer && selection.startOffset === 0 && selection.endOffset === 0) {
451
482
  selectionWasReset = true;
452
483
  }
453
484
  });
454
- editor.on("BeforeExecCommand", () => {
485
+ editor.on('BeforeExecCommand', () => {
455
486
  restoreSelectionIfNecessary();
456
487
  });
457
- editor.on("ExecCommand", (/* event */
488
+ editor.on('ExecCommand', (/* event */
458
489
  ) => {
459
490
  if (!this.editor) return;
460
491
  // Commands may have modified the selection, we need to recapture it
@@ -469,10 +500,10 @@ class RCEWrapper extends React.Component {
469
500
  /* ********** autosave support *************** */
470
501
  this.initAutoSave = editor => {
471
502
  var _this$props$userCache;
472
- this.storage = new EncryptedStorage((_this$props$userCache = this.props.userCacheKey) !== null && _this$props$userCache !== void 0 ? _this$props$userCache : "");
503
+ this.storage = new EncryptedStorage((_this$props$userCache = this.props.userCacheKey) !== null && _this$props$userCache !== void 0 ? _this$props$userCache : '');
473
504
  if (this.storage) {
474
- editor.on("change Undo Redo", this.doAutoSave);
475
- editor.on("blur", this.doAutoSave);
505
+ editor.on('change Undo Redo', this.doAutoSave);
506
+ editor.on('blur', this.doAutoSave);
476
507
  this.cleanupAutoSave();
477
508
  try {
478
509
  const autosaved = this.getAutoSaved(this.autoSaveKey);
@@ -487,7 +518,6 @@ class RCEWrapper extends React.Component {
487
518
  if (autosavedContent !== editorContent) {
488
519
  this.setState({
489
520
  confirmAutoSave: true,
490
- // @ts-expect-error
491
521
  autoSavedContent: patchAutosavedContent(autosaved.content)
492
522
  });
493
523
  } else {
@@ -497,7 +527,7 @@ class RCEWrapper extends React.Component {
497
527
  } catch (ex) {
498
528
  // log and ignore
499
529
 
500
- console.error("Failed initializing rce autosave", ex);
530
+ console.error('Failed initializing rce autosave', ex);
501
531
  }
502
532
  }
503
533
  };
@@ -552,7 +582,7 @@ class RCEWrapper extends React.Component {
552
582
  this.cleanupAutoSave(true);
553
583
  this.doAutoSave(e, true);
554
584
  } else {
555
- console.error("Autosave failed:", ex);
585
+ console.error('Autosave failed:', ex);
556
586
  }
557
587
  }
558
588
  }
@@ -560,7 +590,7 @@ class RCEWrapper extends React.Component {
560
590
  /* *********** end autosave support *************** */
561
591
  this.onWordCountUpdate = e => {
562
592
  if (!this.editor) return;
563
- const shouldIgnore = countShouldIgnore(this.editor, "body", "words");
593
+ const shouldIgnore = countShouldIgnore(this.editor, 'body', 'words');
564
594
  const updatedCount = e.wordCount.words - shouldIgnore;
565
595
  this.setState(state => {
566
596
  if (updatedCount !== state.wordCount) {
@@ -573,7 +603,7 @@ class RCEWrapper extends React.Component {
573
603
  // @ts-expect-error
574
604
  this.onNodeChange = e => {
575
605
  // This is basically copied out of the tinymce silver theme code for the status bar
576
- const path = e.parents.filter(p => p.nodeName !== "BR" && !p.getAttribute("data-mce-bogus") && p.getAttribute("data-mce-type") !== "bookmark")
606
+ const path = e.parents.filter(p => p.nodeName !== 'BR' && !p.getAttribute('data-mce-bogus') && p.getAttribute('data-mce-type') !== 'bookmark')
577
607
  // @ts-expect-error
578
608
  .map(p => p.nodeName.toLowerCase()).reverse();
579
609
  this.setState({
@@ -584,7 +614,7 @@ class RCEWrapper extends React.Component {
584
614
  this.props.onContentChange?.(content);
585
615
  // check accessibility when clearing the editor,
586
616
  // all other times should be checked by handleInputChange
587
- if (content === "") {
617
+ if (content === '') {
588
618
  this.checkAccessibility();
589
619
  }
590
620
  };
@@ -606,14 +636,14 @@ class RCEWrapper extends React.Component {
606
636
  height: newHeight
607
637
  });
608
638
  // play nice and send the same event that the silver theme would send
609
- editor.fire("ResizeEditor", {
639
+ editor.fire('ResizeEditor', {
610
640
  deltaY: coordinates.deltaY
611
641
  });
612
642
  }
613
643
  };
614
644
  this.onA11yChecker = triggerElementId => {
615
645
  const editor = this.mceInstance();
616
- editor.execCommand("openAccessibilityChecker", false, {
646
+ editor.execCommand('openAccessibilityChecker', false, {
617
647
  mountNode: instuiPopupMountNodeFn,
618
648
  triggerElementId,
619
649
  onFixError: errors => {
@@ -627,7 +657,7 @@ class RCEWrapper extends React.Component {
627
657
  };
628
658
  this.checkAccessibility = () => {
629
659
  const editor = this.mceInstance();
630
- editor.execCommand("checkAccessibility", false, {
660
+ editor.execCommand('checkAccessibility', false, {
631
661
  // @ts-expect-error
632
662
  done: errors => {
633
663
  this.setState({
@@ -666,64 +696,6 @@ class RCEWrapper extends React.Component {
666
696
  this.state.KBShortcutFocusReturn?.focus();
667
697
  }
668
698
  };
669
- this.handleAIClick = () => {
670
- import("./plugins/shared/ai_tools").then(module => {
671
- // @ts-expect-error
672
- this.AIToolsTray = module.AIToolsTray;
673
- this.setState({
674
- AIToolsOpen: true,
675
- AITToolsFocusReturn: document.activeElement
676
- });
677
- }).catch(ex => {
678
- console.error("Failed loading the AIToolsTray", ex);
679
- });
680
- };
681
- this.closeAITools = () => {
682
- this.setState({
683
- AIToolsOpen: false
684
- });
685
- };
686
- this.AIToolsExited = () => {
687
- if (this.state.AITToolsFocusReturn === this.iframe) {
688
- // launched using a kb shortcut
689
- // the iframe has focus so we need to forward it on to tinymce editor
690
- if (this.editor) {
691
- this.editor.focus(false);
692
- }
693
- } else if (this.state.AITToolsFocusReturn === document.getElementById(`show-on-focus-btn-${this.id}`)) {
694
- // launched from showOnFocus button
695
- // edge case where focusing KBShortcutFocusReturn doesn't work
696
- this._showOnFocusButton?.focus();
697
- } else {
698
- // launched from kb shortcut button on status bar
699
- // @ts-expect-error
700
- this.state.AITToolsFocusReturn?.focus();
701
- }
702
- };
703
- this.handleInsertAIContent = content => {
704
- const editor = this.mceInstance();
705
- contentInsertion.insertContent(editor, content);
706
- };
707
- this.handleReplaceAIContent = content => {
708
- const ed = this.mceInstance();
709
- const selection = ed.selection;
710
- if (selection.getContent().length > 0) {
711
- selection.setContent(content);
712
- } else {
713
- ed.selection.select(ed.getBody(), true);
714
- selection.setContent(content);
715
- }
716
- };
717
- this.getCurrentContentForAI = () => {
718
- const selected = this.mceInstance().selection.getContent();
719
- return selected ? {
720
- type: "selection",
721
- content: selected
722
- } : {
723
- type: "full",
724
- content: this.mceInstance().getContent()
725
- };
726
- };
727
699
  this.handleTextareaChange = () => {
728
700
  if (this.isHidden()) {
729
701
  this.setCode(this.textareaValue());
@@ -735,7 +707,7 @@ class RCEWrapper extends React.Component {
735
707
  alert.id = alertIdValue++;
736
708
  this.setState(state => {
737
709
  let messages = state.messages.concat(alert);
738
- messages = _.uniqBy(messages, "text"); // Don't show the same message twice
710
+ messages = uniqBy(messages, 'text'); // Don't show the same message twice
739
711
  return {
740
712
  messages
741
713
  };
@@ -754,11 +726,11 @@ class RCEWrapper extends React.Component {
754
726
  */
755
727
  this.resetAlertId = () => {
756
728
  if (this.state.messages.length > 0) {
757
- throw new Error("There are messages currently, you cannot reset when they are non-zero");
729
+ throw new Error('There are messages currently, you cannot reset when they are non-zero');
758
730
  }
759
731
  alertIdValue = 0;
760
732
  };
761
- this.style = buildStyle();
733
+ this.style = buildStyle(!!props.useHighContrast, props.fontFamily);
762
734
 
763
735
  // Set up some limited global state that can be referenced
764
736
  // as needed in RCE's components and function / plugin definitions
@@ -796,7 +768,7 @@ class RCEWrapper extends React.Component {
796
768
  if (!Number.isNaN(_ht)) {
797
769
  _ht = `${_ht}px`;
798
770
  }
799
- const currentRCECount = document.querySelectorAll(".rce-wrapper").length;
771
+ const currentRCECount = document.querySelectorAll('.rce-wrapper').length;
800
772
  const maxInitRenderedRCEs = Number.isNaN(props.maxInitRenderedRCEs) ? RCEWrapper.defaultProps.maxInitRenderedRCEs : props.maxInitRenderedRCEs;
801
773
  this.state = {
802
774
  path: [],
@@ -807,9 +779,9 @@ class RCEWrapper extends React.Component {
807
779
  messages: [],
808
780
  announcement: null,
809
781
  confirmAutoSave: false,
810
- autoSavedContent: "",
782
+ autoSavedContent: '',
811
783
  // @ts-expect-error
812
- id: this.props.id || this.props.textareaId || `${uid("rce", 2)}`,
784
+ id: this.props.id || this.props.textareaId || `${uid('rce', 2)}`,
813
785
  // @ts-expect-error
814
786
  height: _ht,
815
787
  fullscreenState: {
@@ -817,8 +789,7 @@ class RCEWrapper extends React.Component {
817
789
  prevHeight: _ht
818
790
  },
819
791
  a11yErrorsCount: 0,
820
- shouldShowEditor: typeof IntersectionObserver === "undefined" || maxInitRenderedRCEs <= 0 || currentRCECount < maxInitRenderedRCEs,
821
- AIToolsOpen: false
792
+ shouldShowEditor: typeof IntersectionObserver === 'undefined' || maxInitRenderedRCEs <= 0 || currentRCECount < maxInitRenderedRCEs
822
793
  };
823
794
  this._statusBarId = `${this.state.id}_statusbar`;
824
795
  this.pendingEventHandlers = [];
@@ -842,7 +813,6 @@ class RCEWrapper extends React.Component {
842
813
  this.resizeObserver = new ResizeObserver(() => {
843
814
  this._handleFullscreenResize();
844
815
  });
845
- this.AIToolsTray = undefined;
846
816
  this._effectiveContainingContext = normalizeContainingContext(this.props.trayProps?.containingContext);
847
817
  }
848
818
 
@@ -852,11 +822,11 @@ class RCEWrapper extends React.Component {
852
822
  // configure tinymce to say where that div is mounted, do this
853
823
  // is a bit of a hack to tag the div that is this RCE's
854
824
  _tagTinymceAuxDiv() {
855
- const tinyauxlist = document.querySelectorAll(".tox-tinymce-aux");
825
+ const tinyauxlist = document.querySelectorAll('.tox-tinymce-aux');
856
826
  if (tinyauxlist.length) {
857
827
  const myaux = tinyauxlist[tinyauxlist.length - 1];
858
828
  if (myaux.id) {
859
- console.error("Unexpected ID on my tox-tinymce-aux element");
829
+ console.error('Unexpected ID on my tox-tinymce-aux element');
860
830
  }
861
831
  myaux.id = `tinyaux-${this.id}`;
862
832
  }
@@ -871,17 +841,17 @@ class RCEWrapper extends React.Component {
871
841
  rce_transform_loaded_content = false,
872
842
  rce_find_replace = false,
873
843
  rce_studio_embed_improvements = false,
874
- file_verifiers_for_quiz_links = false,
875
- consolidated_media_player = false
844
+ rce_asr_captioning_improvements = false,
845
+ file_verifiers_for_quiz_links = false
876
846
  } = this.props.features;
877
847
  return {
878
848
  new_math_equation_handling,
879
849
  explicit_latex_typesetting,
880
850
  rce_transform_loaded_content,
881
851
  rce_studio_embed_improvements,
852
+ rce_asr_captioning_improvements,
882
853
  file_verifiers_for_quiz_links,
883
- rce_find_replace,
884
- consolidated_media_player
854
+ rce_find_replace
885
855
  };
886
856
  }
887
857
  getRequiredConfigValues() {
@@ -916,7 +886,7 @@ class RCEWrapper extends React.Component {
916
886
  let status = true;
917
887
  // Check for remaining placeholders
918
888
  if (this.mceInstance().dom.doc.querySelector(`[data-placeholder-for]`)) {
919
- status = promptFunc(formatMessage("Content is still being uploaded, if you continue it will not be embedded properly."));
889
+ status = promptFunc(formatMessage('Content is still being uploaded, if you continue it will not be embedded properly.'));
920
890
  }
921
891
  return status;
922
892
  }
@@ -976,9 +946,9 @@ class RCEWrapper extends React.Component {
976
946
  // @ts-expect-error
977
947
  ifr.contentDocument.body.clientHeight -
978
948
  // @ts-expect-error
979
- parseInt(editor_body_style["padding-top"], 10) -
949
+ parseInt(editor_body_style['padding-top'], 10) -
980
950
  // @ts-expect-error
981
- parseInt(editor_body_style["padding-bottom"], 10);
951
+ parseInt(editor_body_style['padding-bottom'], 10);
982
952
  const para_margin_ht = 24;
983
953
  const reserve_ht = Math.ceil(height + para_margin_ht);
984
954
  if (reserve_ht > editor_ht) {
@@ -990,7 +960,7 @@ class RCEWrapper extends React.Component {
990
960
  }
991
961
  }
992
962
  checkImageLoadError(element) {
993
- if (!element || element.tagName !== "IMG") {
963
+ if (!element || element.tagName !== 'IMG') {
994
964
  return;
995
965
  }
996
966
  // @ts-expect-error
@@ -1005,9 +975,9 @@ class RCEWrapper extends React.Component {
1005
975
  // @ts-expect-error
1006
976
  if (element.naturalWidth === 0) {
1007
977
  // @ts-expect-error
1008
- element.style.border = "1px solid #000";
978
+ element.style.border = '1px solid #000';
1009
979
  // @ts-expect-error
1010
- element.style.padding = "2px";
980
+ element.style.padding = '2px';
1011
981
  }
1012
982
  }, 0);
1013
983
  }
@@ -1017,7 +987,7 @@ class RCEWrapper extends React.Component {
1017
987
  this.contentInserted(element);
1018
988
  }
1019
989
  replaceCode(code) {
1020
- if (code !== "" && window.confirm(formatMessage("Content in the editor will be changed. Press Cancel to keep the original content."))) {
990
+ if (code !== '' && window.confirm(formatMessage('Content in the editor will be changed. Press Cancel to keep the original content.'))) {
1021
991
  this.mceInstance().setContent(code);
1022
992
  }
1023
993
  }
@@ -1034,12 +1004,12 @@ class RCEWrapper extends React.Component {
1034
1004
  // that there's some embedded content helper
1035
1005
  // From what I've read, "title" is more reliable than "aria-label" for
1036
1006
  // elements like iframes and embeds.
1037
- const temp = document.createElement("div");
1007
+ const temp = document.createElement('div');
1038
1008
  temp.innerHTML = code;
1039
1009
  const code_elem = temp.firstElementChild;
1040
1010
  if (code_elem) {
1041
- if (!code_elem.hasAttribute("title") && !code_elem.hasAttribute("aria-label")) {
1042
- code_elem.setAttribute("title", formatMessage("embedded content"));
1011
+ if (!code_elem.hasAttribute('title') && !code_elem.hasAttribute('aria-label')) {
1012
+ code_elem.setAttribute('title', formatMessage('embedded content'));
1043
1013
  }
1044
1014
  code = code_elem.outerHTML;
1045
1015
  }
@@ -1049,7 +1019,7 @@ class RCEWrapper extends React.Component {
1049
1019
  // and it's often inserted into a <p> on top of that. Find the
1050
1020
  // iframe and use it to flash the indicator.
1051
1021
  const element = contentInsertion.insertContent(editor, code);
1052
- const ifr = element && element.querySelector && element.querySelector("iframe");
1022
+ const ifr = element && element.querySelector && element.querySelector('iframe');
1053
1023
  if (ifr) {
1054
1024
  this.contentInserted(ifr);
1055
1025
  } else {
@@ -1061,7 +1031,7 @@ class RCEWrapper extends React.Component {
1061
1031
  const element = contentInsertion.insertImage(editor, image, this.getCanvasUrl());
1062
1032
 
1063
1033
  // Removes TinyMCE's caret &nbsp; text if exists.
1064
- if (element?.nextSibling?.data?.startsWith("\xA0" /* nbsp */)) {
1034
+ if (element?.nextSibling?.data?.startsWith('\xA0' /* nbsp */)) {
1065
1035
  element.nextSibling.splitText(1);
1066
1036
  element.nextSibling.remove();
1067
1037
  }
@@ -1142,8 +1112,8 @@ class RCEWrapper extends React.Component {
1142
1112
  onTinyMCEInstance(command, ...args) {
1143
1113
  const editor = this.mceInstance();
1144
1114
  if (editor) {
1145
- if (command === "mceRemoveEditor") {
1146
- editor.execCommand("mceNewDocument");
1115
+ if (command === 'mceRemoveEditor') {
1116
+ editor.execCommand('mceNewDocument');
1147
1117
  } // makes sure content can't persist past removal
1148
1118
  editor.execCommand(command, false, ...args);
1149
1119
  }
@@ -1163,17 +1133,17 @@ class RCEWrapper extends React.Component {
1163
1133
  return null;
1164
1134
  }
1165
1135
  textareaValue() {
1166
- return this.getTextarea()?.value || "";
1136
+ return this.getTextarea()?.value || '';
1167
1137
  }
1168
1138
  get id() {
1169
1139
  return this.state.id;
1170
1140
  }
1171
1141
  getHtmlEditorStorage() {
1172
- const cookieValue = getCookie("rce.htmleditor");
1142
+ const cookieValue = getCookie('rce.htmleditor');
1173
1143
  if (cookieValue) {
1174
1144
  document.cookie = `rce.htmleditor=${cookieValue};path=/;max-age=0`;
1175
1145
  }
1176
- const value = cookieValue || this.storage?.getItem?.("rce.htmleditor")?.content;
1146
+ const value = cookieValue || this.storage?.getItem?.('rce.htmleditor')?.content;
1177
1147
  return value === RAW_HTML_EDITOR_VIEW || value === PRETTY_HTML_EDITOR_VIEW ? value : PRETTY_HTML_EDITOR_VIEW;
1178
1148
  }
1179
1149
  _isFullscreen() {
@@ -1190,7 +1160,7 @@ class RCEWrapper extends React.Component {
1190
1160
  this._elementRef.current?.appendChild(tinymenuhost);
1191
1161
  }
1192
1162
  this._elementRef.current?.addEventListener(FS_CHANGEEVENT, this._onFullscreenChange);
1193
- if (typeof this._elementRef.current?.offsetHeight === "number") {
1163
+ if (typeof this._elementRef.current?.offsetHeight === 'number') {
1194
1164
  this.setState({
1195
1165
  fullscreenState: {
1196
1166
  prevHeight: this._elementRef.current.offsetHeight - this._getStatusBarHeight()
@@ -1222,7 +1192,7 @@ class RCEWrapper extends React.Component {
1222
1192
  const container = ed.getContainer();
1223
1193
  if (container) {
1224
1194
  container.style.height = cssHeight;
1225
- ed.fire("ResizeEditor");
1195
+ ed.fire('ResizeEditor');
1226
1196
  }
1227
1197
  const textarea = this.getTextarea();
1228
1198
  if (textarea) {
@@ -1233,10 +1203,10 @@ class RCEWrapper extends React.Component {
1233
1203
  });
1234
1204
  }
1235
1205
  focus() {
1236
- this.onTinyMCEInstance("mceFocus");
1206
+ this.onTinyMCEInstance('mceFocus');
1237
1207
  // tinymce doesn't always call the focus handler.
1238
1208
  // @ts-expect-error
1239
- this.handleFocusEditor(new Event("focus", {
1209
+ this.handleFocusEditor(new Event('focus', {
1240
1210
  target: this.mceInstance()
1241
1211
  }));
1242
1212
  }
@@ -1274,7 +1244,7 @@ class RCEWrapper extends React.Component {
1274
1244
  */
1275
1245
  get _mceSerializedInitialHtml() {
1276
1246
  if (!this._mceSerializedInitialHtmlCached) {
1277
- const el = window.document.createElement("div");
1247
+ const el = window.document.createElement('div');
1278
1248
  // @ts-expect-error
1279
1249
  el.innerHTML = this.initialContent;
1280
1250
  const serializer = this.mceInstance().serializer;
@@ -1328,22 +1298,22 @@ class RCEWrapper extends React.Component {
1328
1298
  // focus is still somewhere w/in me
1329
1299
  return;
1330
1300
  }
1331
- const activeClass = document.activeElement?.getAttribute("class");
1301
+ const activeClass = document.activeElement?.getAttribute('class');
1332
1302
  if (
1333
1303
  // @ts-expect-error
1334
1304
  (event.focusedEditor === undefined ||
1335
1305
  // @ts-expect-error
1336
- event.target.id === event.focusedEditor?.id) && activeClass?.includes("tox-")) {
1306
+ event.target.id === event.focusedEditor?.id) && activeClass?.includes('tox-')) {
1337
1307
  // if a toolbar button has focus, then the user clicks on the "more" button
1338
1308
  // focus jumps to the body, then eventually to the popped up toolbar. This
1339
1309
  // catches that case.
1340
1310
  return;
1341
1311
  }
1342
- if (event?.relatedTarget?.getAttribute("class")?.includes("tox-")) {
1312
+ if (event?.relatedTarget?.getAttribute('class')?.includes('tox-')) {
1343
1313
  // a tinymce popup has focus
1344
1314
  return;
1345
1315
  }
1346
- const popups = document.querySelectorAll("[data-mce-component]");
1316
+ const popups = document.querySelectorAll('[data-mce-component]');
1347
1317
  for (const popup of popups) {
1348
1318
  if (popup.contains(document.activeElement)) {
1349
1319
  // one of our popups has focus
@@ -1361,22 +1331,22 @@ class RCEWrapper extends React.Component {
1361
1331
  call(methodName, ...args) {
1362
1332
  // since exists? has a ? and cant be a regular function just return true
1363
1333
  // rather than calling as a fn on the editor
1364
- if (methodName === "exists?") {
1334
+ if (methodName === 'exists?') {
1365
1335
  return true;
1366
1336
  }
1367
1337
  // @ts-expect-error
1368
1338
  return this[methodName](...args);
1369
1339
  }
1370
1340
  announceContextToolbars(editor) {
1371
- editor.on("NodeChange", () => {
1341
+ editor.on('NodeChange', () => {
1372
1342
  if (!this._isMounted) return;
1373
1343
  const node = editor.selection.getNode();
1374
1344
  // @ts-expect-error
1375
1345
  if (isImageEmbed(node, editor)) {
1376
1346
  if (this.announcing !== 1) {
1377
1347
  this.setState({
1378
- announcement: formatMessage("type Control F9 to access image options. {text}", {
1379
- text: node.getAttribute("alt")
1348
+ announcement: formatMessage('type Control F9 to access image options. {text}', {
1349
+ text: node.getAttribute('alt')
1380
1350
  })
1381
1351
  });
1382
1352
  this.announcing = 1;
@@ -1384,7 +1354,7 @@ class RCEWrapper extends React.Component {
1384
1354
  } else if (isFileLink(node, editor)) {
1385
1355
  if (this.announcing !== 2) {
1386
1356
  this.setState({
1387
- announcement: formatMessage("type Control F9 to access link options. {text}", {
1357
+ announcement: formatMessage('type Control F9 to access link options. {text}', {
1388
1358
  text: node.textContent
1389
1359
  })
1390
1360
  });
@@ -1393,7 +1363,7 @@ class RCEWrapper extends React.Component {
1393
1363
  } else if (isElementWithinTable(node)) {
1394
1364
  if (this.announcing !== 3) {
1395
1365
  this.setState({
1396
- announcement: formatMessage("type Control F9 to access table options. {text}", {
1366
+ announcement: formatMessage('type Control F9 to access table options. {text}', {
1397
1367
  text: node.textContent
1398
1368
  })
1399
1369
  });
@@ -1406,17 +1376,17 @@ class RCEWrapper extends React.Component {
1406
1376
  this.announcing = 0;
1407
1377
  }
1408
1378
  });
1409
- editor.on("ResizeEditor", ({
1379
+ editor.on('ResizeEditor', ({
1410
1380
  deltaY
1411
1381
  }) => {
1412
1382
  if (!this._isMounted || !deltaY) return;
1413
1383
  if (deltaY < 0) {
1414
1384
  this.setState({
1415
- announcement: formatMessage("The height of Rich Content Area is decreased.")
1385
+ announcement: formatMessage('The height of Rich Content Area is decreased.')
1416
1386
  });
1417
1387
  } else {
1418
1388
  this.setState({
1419
- announcement: formatMessage("The height of Rich Content Area is increased.")
1389
+ announcement: formatMessage('The height of Rich Content Area is increased.')
1420
1390
  });
1421
1391
  }
1422
1392
  });
@@ -1442,10 +1412,10 @@ class RCEWrapper extends React.Component {
1442
1412
  // This doesn't apply if the editor is off-screen or has visibility:hidden;
1443
1413
  // only if it isn't rendered or has display:none;
1444
1414
  const editorVisible = this.editor.getContainer().offsetParent;
1445
- return this.props.autosave?.enabled && editorVisible && document.querySelectorAll(".rce-wrapper").length === 1 && storageAvailable();
1415
+ return this.props.autosave?.enabled && editorVisible && document.querySelectorAll('.rce-wrapper').length === 1 && storageAvailable();
1446
1416
  }
1447
1417
  get autoSaveKey() {
1448
- const userId = this._effectiveContainingContext?.userId || "-";
1418
+ const userId = this._effectiveContainingContext?.userId || '-';
1449
1419
  return `rceautosave:${userId}${window.location.href}:${this.props.textareaId}`;
1450
1420
  }
1451
1421
  componentWillUnmount() {
@@ -1456,7 +1426,7 @@ class RCEWrapper extends React.Component {
1456
1426
  this.destroy();
1457
1427
  }
1458
1428
  if (this._elementRef.current) {
1459
- this._elementRef.current.removeEventListener("keydown", this.handleKey, true);
1429
+ this._elementRef.current.removeEventListener('keydown', this.handleKey, true);
1460
1430
  }
1461
1431
  this.mutationObserver?.disconnect();
1462
1432
  this.intersectionObserver?.disconnect();
@@ -1468,27 +1438,27 @@ class RCEWrapper extends React.Component {
1468
1438
 
1469
1439
  // @ts-expect-error
1470
1440
  const setupCallback = options.setup;
1471
- const canvasPlugins = rcsExists ? ["instructure_image", "instructure_documents", "instructure_equation"] : [];
1441
+ const canvasPlugins = rcsExists ? ['instructure_image', 'instructure_documents', 'instructure_equation'] : [];
1472
1442
  if (rcsExists && !this.props.instRecordDisabled) {
1473
- canvasPlugins.splice(2, 0, "instructure_record");
1443
+ canvasPlugins.splice(2, 0, 'instructure_record');
1474
1444
  }
1475
- const pastePlugins = rcsExists ? ["instructure_paste", "paste"] : ["paste"];
1476
- if (rcsExists && this.props.use_rce_icon_maker && this.props.trayProps?.contextType === "course") {
1477
- canvasPlugins.push("instructure_icon_maker");
1445
+ const pastePlugins = rcsExists ? ['instructure_paste', 'paste'] : ['paste'];
1446
+ if (rcsExists && this.props.use_rce_icon_maker && this.props.trayProps?.contextType === 'course') {
1447
+ canvasPlugins.push('instructure_icon_maker');
1478
1448
  }
1479
1449
  if (document[FS_ENABLED]) {
1480
- canvasPlugins.push("instructure_fullscreen");
1450
+ canvasPlugins.push('instructure_fullscreen');
1481
1451
  }
1482
1452
  if (this.getRequiredFeatureStatuses().rce_find_replace) {
1483
- canvasPlugins.push("searchreplace");
1484
- canvasPlugins.push("instructure_search_and_replace");
1453
+ canvasPlugins.push('searchreplace');
1454
+ canvasPlugins.push('instructure_search_and_replace');
1485
1455
  }
1486
- const possibleNewMenubarItems = this.props.editorOptions.menu ? Object.keys(this.props.editorOptions.menu).join(" ") : undefined;
1456
+ const possibleNewMenubarItems = this.props.editorOptions.menu ? Object.keys(this.props.editorOptions.menu).join(' ') : undefined;
1487
1457
  const wrappedOpts = {
1488
1458
  ...defaultTinymceConfig,
1489
1459
  ...options,
1490
1460
  readonly: this.props.readOnly,
1491
- theme: "silver",
1461
+ theme: 'silver',
1492
1462
  // some older code specified 'modern', which doesn't exist any more
1493
1463
 
1494
1464
  // @ts-expect-error
@@ -1497,7 +1467,7 @@ class RCEWrapper extends React.Component {
1497
1467
  document_base_url: this.props.canvasOrigin,
1498
1468
  block_formats:
1499
1469
  // @ts-expect-error
1500
- options.block_formats || [`${formatMessage("Heading 2")}=h2`, `${formatMessage("Heading 3")}=h3`, `${formatMessage("Heading 4")}=h4`, `${formatMessage("Preformatted")}=pre`, `${formatMessage("Paragraph")}=p`].join("; "),
1470
+ options.block_formats || [`${formatMessage('Heading 2')}=h2`, `${formatMessage('Heading 3')}=h3`, `${formatMessage('Heading 4')}=h4`, `${formatMessage('Preformatted')}=pre`, `${formatMessage('Paragraph')}=p`].join('; '),
1501
1471
  setup: editor => {
1502
1472
  addKebabIcon(editor);
1503
1473
  editorWrappers.set(editor, this);
@@ -1510,7 +1480,7 @@ class RCEWrapper extends React.Component {
1510
1480
  // @ts-expect-error
1511
1481
  bridge.userLocale = userLocale;
1512
1482
  bridge.canvasOrigin = this.props.canvasOrigin;
1513
- if (typeof setupCallback === "function") {
1483
+ if (typeof setupCallback === 'function') {
1514
1484
  setupCallback(editor);
1515
1485
  }
1516
1486
  },
@@ -1521,7 +1491,7 @@ class RCEWrapper extends React.Component {
1521
1491
  // @ts-expect-error
1522
1492
  content_css: options.content_css || [],
1523
1493
  // @ts-expect-error
1524
- content_style: contentCSS + (options.content_style || ""),
1494
+ content_style: contentCSS + (options.content_style || ''),
1525
1495
  menubar: mergeMenuItems(getMenubarForVariant(this.variant), possibleNewMenubarItems),
1526
1496
  // default menu options listed at https://www.tiny.cloud/docs/configure/editor-appearance/#menu
1527
1497
  // tinymce's default edit and table menus are fine
@@ -1536,10 +1506,10 @@ class RCEWrapper extends React.Component {
1536
1506
  getToolbarForVariant(this.variant, this.ltiToolFavorites),
1537
1507
  // @ts-expect-error
1538
1508
  options.toolbar),
1539
- contextmenu: "",
1509
+ contextmenu: '',
1540
1510
  // show the browser's native context menu
1541
1511
 
1542
- toolbar_mode: "sliding",
1512
+ toolbar_mode: 'sliding',
1543
1513
  toolbar_sticky: true,
1544
1514
  // In regards to the ability to disable plugins:
1545
1515
  // we only have to explicitly manage the removal of plugins
@@ -1548,16 +1518,16 @@ class RCEWrapper extends React.Component {
1548
1518
  // handles all of that complexity. It that ever changes in the
1549
1519
  // future in an upgraded version, we will have to update the
1550
1520
  // logic in those other places as well.
1551
- plugins: mergePlugins(["autolink", "media", "table", "link", "directionality", "lists", "textpattern", "hr", "instructure_color", "instructure-ui-icons", "instructure_condensed_buttons", "instructure_links", "instructure_html_view", "instructure_media_embed", "a11y_checker", "wordcount", "instructure_wordcount", "instructure_wordcount_header", "instructure_keyboard_shortcuts_header", "instructure_studio_media_options", "instructure_rce_external_tools", ...pastePlugins, ...canvasPlugins],
1521
+ plugins: mergePlugins(['autolink', 'media', 'table', 'link', 'directionality', 'lists', 'textpattern', 'hr', 'instructure_color', 'instructure-ui-icons', 'instructure_condensed_buttons', 'instructure_links', 'instructure_html_view', 'instructure_media_embed', 'a11y_checker', 'wordcount', 'instructure_wordcount', 'instructure_wordcount_header', 'instructure_keyboard_shortcuts_header', 'instructure_studio_media_options', 'instructure_rce_external_tools', ...pastePlugins, ...canvasPlugins],
1552
1522
  // filter out the plugins designated for removal
1553
1523
  // @ts-expect-error
1554
- sanitizePlugins(options.plugins)?.filter(p => p.length > 0 && p[0] !== "-"), this.pluginsToExclude),
1524
+ sanitizePlugins(options.plugins)?.filter(p => p.length > 0 && p[0] !== '-'), this.pluginsToExclude),
1555
1525
  textpattern_patterns: [{
1556
- start: "* ",
1557
- cmd: "InsertUnorderedList"
1526
+ start: '* ',
1527
+ cmd: 'InsertUnorderedList'
1558
1528
  }, {
1559
- start: "- ",
1560
- cmd: "InsertUnorderedList"
1529
+ start: '- ',
1530
+ cmd: 'InsertUnorderedList'
1561
1531
  }]
1562
1532
  };
1563
1533
  if (this.props.trayProps) {
@@ -1579,7 +1549,7 @@ class RCEWrapper extends React.Component {
1579
1549
  }
1580
1550
  unhandleTextareaChange() {
1581
1551
  if (this._textareaEl) {
1582
- this._textareaEl.removeEventListener("input", this.handleTextareaChange);
1552
+ this._textareaEl.removeEventListener('input', this.handleTextareaChange);
1583
1553
  }
1584
1554
  }
1585
1555
  registerTextareaChange() {
@@ -1587,7 +1557,7 @@ class RCEWrapper extends React.Component {
1587
1557
  if (this._textareaEl !== el) {
1588
1558
  this.unhandleTextareaChange();
1589
1559
  if (el) {
1590
- el.addEventListener("input", this.handleTextareaChange);
1560
+ el.addEventListener('input', this.handleTextareaChange);
1591
1561
  if (this.props.textareaClassName) {
1592
1562
  // split the string on whitespace because classList doesn't let you add multiple
1593
1563
  // space seperated classes at a time but does let you add an array of them
@@ -1613,7 +1583,7 @@ class RCEWrapper extends React.Component {
1613
1583
  // initialize the RCE when it gets close to entering the viewport
1614
1584
  {
1615
1585
  root: null,
1616
- rootMargin: "200px 0px",
1586
+ rootMargin: '200px 0px',
1617
1587
  threshold: 0.0
1618
1588
  });
1619
1589
  // @ts-expect-error
@@ -1632,7 +1602,7 @@ class RCEWrapper extends React.Component {
1632
1602
  this.focusCurrentView();
1633
1603
  }
1634
1604
  if (prevProps.readOnly !== this.props.readOnly) {
1635
- this.mceInstance().mode.set(this.props.readOnly ? "readonly" : "design");
1605
+ this.mceInstance().mode.set(this.props.readOnly ? 'readonly' : 'design');
1636
1606
  }
1637
1607
  }
1638
1608
  }
@@ -1646,7 +1616,7 @@ class RCEWrapper extends React.Component {
1646
1616
  this._tagTinymceAuxDiv();
1647
1617
  this.registerTextareaChange();
1648
1618
  // @ts-expect-error
1649
- this._elementRef.current.addEventListener("keydown", this.handleKey, true);
1619
+ this._elementRef.current.addEventListener('keydown', this.handleKey, true);
1650
1620
  // give the textarea its initial size
1651
1621
  this.onResize(null, {
1652
1622
  deltaY: 0
@@ -1654,7 +1624,7 @@ class RCEWrapper extends React.Component {
1654
1624
  // Preload the LTI Tools modal
1655
1625
  // This helps with loading the favorited external tools
1656
1626
  if (this.ltiToolFavorites.length > 0) {
1657
- import("./plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog");
1627
+ import('./plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog');
1658
1628
  }
1659
1629
  bridge.renderEditor(this);
1660
1630
  }
@@ -1676,9 +1646,9 @@ class RCEWrapper extends React.Component {
1676
1646
  fallback: /*#__PURE__*/React.createElement("div", {
1677
1647
  style: {
1678
1648
  height: this.state.height,
1679
- display: "flex",
1680
- justifyContent: "center",
1681
- alignItems: "center"
1649
+ display: 'flex',
1650
+ justifyContent: 'center',
1651
+ alignItems: 'center'
1682
1652
  }
1683
1653
  }, /*#__PURE__*/React.createElement(Spinner, {
1684
1654
  renderTitle: renderLoading,
@@ -1714,12 +1684,11 @@ class RCEWrapper extends React.Component {
1714
1684
  ref: this._editorPlaceholderRef,
1715
1685
  style: {
1716
1686
  height: `${this.props.editorOptions.height}px`,
1717
- border: "1px solid grey"
1687
+ border: '1px solid grey'
1718
1688
  }
1719
1689
  });
1720
1690
  }
1721
1691
  const statusBarOptions = {
1722
- aiTextTools: this.props.ai_text_tools,
1723
1692
  isDesktop: tinymce.Env.deviceType.isDesktop(),
1724
1693
  a11yResizers: !!this.props.features?.rce_a11y_resize
1725
1694
  };
@@ -1740,8 +1709,8 @@ class RCEWrapper extends React.Component {
1740
1709
  // @ts-expect-error
1741
1710
  ,
1742
1711
  ref: this._elementRef,
1743
- style: this.variant === "full" ? {
1744
- marginBottom: ".5rem"
1712
+ style: this.variant === 'full' ? {
1713
+ marginBottom: '.5rem'
1745
1714
  } : undefined,
1746
1715
  onFocus: this.handleFocusRCE,
1747
1716
  onBlur: this.handleBlurRCE
@@ -1749,7 +1718,7 @@ class RCEWrapper extends React.Component {
1749
1718
  id: `show-on-focus-btn-${this.id}`,
1750
1719
  onClick: this.openKBShortcutModal,
1751
1720
  margin: "xx-small",
1752
- screenReaderLabel: formatMessage("View keyboard shortcuts")
1721
+ screenReaderLabel: formatMessage('View keyboard shortcuts')
1753
1722
  // @ts-expect-error
1754
1723
  ,
1755
1724
  ref: el => this._showOnFocusButton = el
@@ -1761,7 +1730,7 @@ class RCEWrapper extends React.Component {
1761
1730
  afterDismiss: this.removeAlert
1762
1731
  }), this.state.editorView === PRETTY_HTML_EDITOR_VIEW && this.renderHtmlEditor(), /*#__PURE__*/React.createElement("div", {
1763
1732
  style: {
1764
- display: this.state.editorView === PRETTY_HTML_EDITOR_VIEW ? "none" : "block"
1733
+ display: this.state.editorView === PRETTY_HTML_EDITOR_VIEW ? 'none' : 'block'
1765
1734
  }
1766
1735
  }, /*#__PURE__*/React.createElement(Editor, {
1767
1736
  id: mceProps.textareaId,
@@ -1809,8 +1778,7 @@ class RCEWrapper extends React.Component {
1809
1778
  skipEditorFocus: true
1810
1779
  }),
1811
1780
  disabledPlugins: this.pluginsToExclude,
1812
- features: statusBarFeatures,
1813
- onAI: this.handleAIClick
1781
+ features: statusBarFeatures
1814
1782
  }), this._effectiveContainingContext && /*#__PURE__*/React.createElement(CanvasContentTray, Object.assign({
1815
1783
  mountNode: instuiPopupMountNodeFn,
1816
1784
  key: this.id,
@@ -1828,19 +1796,6 @@ class RCEWrapper extends React.Component {
1828
1796
  onExited: this.KBShortcutModalExited,
1829
1797
  onDismiss: this.closeKBShortcutModal,
1830
1798
  open: this.state.KBShortcutModalOpen
1831
- }), this.props.ai_text_tools && this.AIToolsTray &&
1832
- /*#__PURE__*/
1833
- // @ts-expect-error
1834
- React.createElement(this.AIToolsTray, {
1835
- open: this.state.AIToolsOpen,
1836
- container: document.querySelector('[role="main"]'),
1837
- mountNode: instuiPopupMountNodeFn,
1838
- contextId: trayProps.contextId,
1839
- contextType: trayProps.contextId,
1840
- currentContent: this.getCurrentContentForAI(),
1841
- onClose: this.closeAITools,
1842
- onInsertContent: this.handleInsertAIContent,
1843
- onReplaceContent: this.handleReplaceAIContent
1844
1799
  }), this.state.confirmAutoSave ? /*#__PURE__*/React.createElement(Suspense, {
1845
1800
  fallback: /*#__PURE__*/React.createElement(Spinner, {
1846
1801
  renderTitle: renderLoading,
@@ -1859,7 +1814,6 @@ class RCEWrapper extends React.Component {
1859
1814
  }
1860
1815
  }
1861
1816
  RCEWrapper.propTypes = {
1862
- ai_text_tools: _pt.bool,
1863
1817
  autosave: _pt.shape({
1864
1818
  enabled: _pt.bool,
1865
1819
  maxAge: _pt.number
@@ -1885,6 +1839,8 @@ RCEWrapper.propTypes = {
1885
1839
  textareaId: _pt.string,
1886
1840
  tinymce: _pt.any.isRequired,
1887
1841
  use_rce_icon_maker: _pt.bool,
1842
+ useHighContrast: _pt.bool,
1843
+ fontFamily: _pt.string,
1888
1844
  userCacheKey: _pt.string
1889
1845
  };
1890
1846
  RCEWrapper.propTypes = rceWrapperPropTypes;
@@ -1898,8 +1854,8 @@ RCEWrapper.defaultProps = {
1898
1854
  maxInitRenderedRCEs: -1,
1899
1855
  features: {},
1900
1856
  timezone: Intl?.DateTimeFormat()?.resolvedOptions()?.timeZone,
1901
- canvasOrigin: "",
1902
- variant: "full"
1857
+ canvasOrigin: '',
1858
+ variant: 'full'
1903
1859
  };
1904
1860
  RCEWrapper.skinCssInjected = false;
1905
1861
  export default RCEWrapper;