@instructure/canvas-rce 5.14.1 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/DEVELOPMENT.md +2 -2
- package/README.md +0 -8
- package/__tests__/common/indicate.test.js +84 -0
- package/__tests__/common/mimeClass.test.js +85 -0
- package/__tests__/module/contentInsertionUtils.test.js +52 -0
- package/__tests__/module/indicatorRegion.test.js +75 -0
- package/__tests__/module/normalizeLocale.test.js +46 -0
- package/__tests__/module/normalizeProps.test.js +51 -0
- package/__tests__/module/sanitizePlugins.test.js +48 -0
- package/__tests__/module/wrapInitCb.test.js +56 -0
- package/__tests__/rcs/api.test.js +819 -0
- package/{mocha-reporter-config.js → __tests__/sidebar/actions/all_files.test.js} +10 -9
- package/__tests__/sidebar/actions/data.test.js +196 -0
- package/__tests__/sidebar/actions/utils.js +44 -0
- package/{es/rce/__mocks__/_mockStudioPlayer.js → __tests__/sidebar/reducers/all_files.test.js} +12 -4
- package/babel.config.js +3 -1
- package/es/bridge/Bridge.js +18 -73
- package/es/bridge/index.js +1 -0
- package/es/canvasFileBrowser/FileBrowser.js +21 -77
- package/es/canvasFileBrowser/en-US.js +3 -6
- package/es/common/FlashAlert.js +15 -39
- package/es/common/browser.js +4 -2
- package/es/common/fileUrl.js +105 -64
- package/es/common/incremental-loading/LoadMoreButton.js +4 -4
- package/es/common/incremental-loading/LoadingIndicator.js +1 -2
- package/es/common/incremental-loading/LoadingStatus.js +5 -13
- package/es/common/incremental-loading/index.js +1 -0
- package/es/common/incremental-loading/useIncrementalLoading.js +1 -3
- package/es/common/indicate.js +16 -10
- package/es/common/mimeClass.js +3 -4
- package/es/common/natcompare.js +1 -4
- package/es/defaultTinymceConfig.js +5 -3
- package/es/elementDenylist.js +1 -0
- package/es/enhance-user-content/doc_previews.js +24 -35
- package/es/enhance-user-content/enhance_user_content.js +32 -67
- package/es/enhance-user-content/external_links.js +6 -9
- package/es/enhance-user-content/index.js +1 -0
- package/es/enhance-user-content/instructure_helper.js +22 -50
- package/es/enhance-user-content/jqueryish_funcs.js +8 -11
- package/es/enhance-user-content/mathml.js +48 -107
- package/es/enhance-user-content/media_comment_thumbnail.js +6 -25
- package/es/format-message.js +4 -5
- package/es/getThemeVars.js +8 -6
- package/es/getTranslations.js +1 -78
- package/es/index.d.ts +59 -0
- package/es/index.js +6 -6
- package/es/rce/AlertMessageArea.js +15 -16
- package/es/rce/DraggingBlocker.js +4 -2
- package/es/rce/KeyboardShortcutModal.js +3 -2
- package/es/rce/RCE.js +16 -17
- package/es/rce/RCEGlobals.js +12 -10
- package/es/rce/RCEVariants.js +29 -14
- package/es/rce/RCEWrapper.js +530 -641
- package/es/rce/RCEWrapper.utils.js +131 -0
- package/es/rce/RCEWrapperProps.js +9 -5
- package/es/rce/RceHtmlEditor.js +17 -19
- package/es/rce/ResizeHandle.js +4 -10
- package/es/rce/RestoreAutoSaveModal.js +1 -2
- package/es/rce/ShowOnFocusButton/index.js +2 -8
- package/es/rce/StatusBar.js +10 -44
- package/es/rce/alertHandler.js +1 -4
- package/es/rce/contentInsertion.js +36 -59
- package/es/rce/contentInsertionUtils.js +6 -8
- package/es/rce/contentRendering.js +13 -17
- package/es/rce/customEvents.js +1 -0
- package/es/rce/editorLanguage.js +23 -11
- package/es/rce/indicatorRegion.js +7 -7
- package/es/rce/normalizeLocale.js +5 -3
- package/es/rce/normalizeProps.js +7 -5
- package/es/rce/plugins/instructure-ui-icons/plugin.js +21 -3
- package/es/rce/plugins/instructure_color/clickCallback.js +82 -0
- package/es/rce/plugins/instructure_color/components/ColorPicker.js +294 -0
- package/es/rce/plugins/instructure_color/components/ColorPopup.js +67 -0
- package/es/rce/plugins/instructure_color/components/colorUtils.js +60 -0
- package/es/rce/plugins/instructure_color/plugin.js +40 -0
- package/es/rce/plugins/instructure_condensed_buttons/core/ListUtils.js +10 -3
- package/es/rce/plugins/instructure_condensed_buttons/plugin.js +1 -0
- package/es/rce/plugins/instructure_condensed_buttons/ui/alignment-button.js +1 -2
- package/es/rce/plugins/instructure_condensed_buttons/ui/directionality-button.js +3 -2
- package/es/rce/plugins/instructure_condensed_buttons/ui/indent-outdent-button.js +1 -0
- package/es/rce/plugins/instructure_condensed_buttons/ui/list-button.js +26 -25
- package/es/rce/plugins/instructure_condensed_buttons/ui/subscript-superscript-button.js +2 -3
- package/es/rce/plugins/instructure_documents/clickCallback.js +1 -0
- package/es/rce/plugins/instructure_documents/components/DocumentsPanel.js +1 -9
- package/es/rce/plugins/instructure_documents/components/Link.js +4 -20
- package/es/rce/plugins/instructure_documents/plugin.js +7 -14
- package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.js +4 -2
- package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedPreference.js +1 -2
- package/es/rce/plugins/instructure_equation/EquationEditorModal/index.js +17 -37
- package/es/rce/plugins/instructure_equation/EquationEditorModal/latexTextareaUtil.js +14 -15
- package/es/rce/plugins/instructure_equation/EquationEditorModal/parseLatex.js +6 -5
- package/es/rce/plugins/instructure_equation/EquationEditorModal/styles.js +4 -2
- package/es/rce/plugins/instructure_equation/EquationEditorToolbar/buttons.js +14 -8
- package/es/rce/plugins/instructure_equation/EquationEditorToolbar/index.js +13 -18
- package/es/rce/plugins/instructure_equation/MathIcon/index.js +4 -5
- package/es/rce/plugins/instructure_equation/MathIcon/svgs.js +1 -1
- package/es/rce/plugins/instructure_equation/clickCallback.js +2 -5
- package/es/rce/plugins/instructure_equation/mathlive/index.js +167 -16
- package/es/rce/plugins/instructure_equation/plugin.js +7 -10
- package/es/rce/plugins/instructure_fullscreen/plugin.js +1 -6
- package/es/rce/plugins/instructure_html_view/clickCallback.js +1 -0
- package/es/rce/plugins/instructure_html_view/plugin.js +5 -4
- package/es/rce/plugins/instructure_icon_maker/clickCallback.js +5 -8
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ColorSection.js +47 -51
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/CreateIconMakerForm.js +10 -10
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Footer.js +11 -11
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Group.js +6 -6
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Header.js +8 -10
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/Course.js +32 -31
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageOptions.js +24 -35
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageSection.js +32 -32
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ModeSelect.js +11 -11
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/MultiColor/index.js +16 -15
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/MultiColor/svg.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/SVGList.js +11 -11
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/SVGThumbnail.js +9 -13
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/SingleColor/index.js +12 -13
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/SingleColor/svg.js +33 -80
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/Upload.js +34 -28
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/index.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/propTypes.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/utils.js +5 -5
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Preview.js +7 -8
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ShapeSection.js +5 -7
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/TextSection.js +5 -10
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/index.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/IconMakerTray.js +38 -60
- package/es/rce/plugins/instructure_icon_maker/components/SavedIconMakerList.js +4 -4
- package/es/rce/plugins/instructure_icon_maker/plugin.js +10 -14
- package/es/rce/plugins/instructure_icon_maker/reducers/imageSection.js +37 -38
- package/es/rce/plugins/instructure_icon_maker/reducers/svgSettings.js +24 -24
- package/es/rce/plugins/instructure_icon_maker/registerEditToolbar.js +2 -4
- package/es/rce/plugins/instructure_icon_maker/svg/constants.js +4 -3
- package/es/rce/plugins/instructure_icon_maker/svg/font.js +3 -1
- package/es/rce/plugins/instructure_icon_maker/svg/image.js +74 -90
- package/es/rce/plugins/instructure_icon_maker/svg/index.js +17 -24
- package/es/rce/plugins/instructure_icon_maker/svg/metadata.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/svg/settings.js +48 -58
- package/es/rce/plugins/instructure_icon_maker/svg/shape.js +5 -54
- package/es/rce/plugins/instructure_icon_maker/svg/text.js +35 -124
- package/es/rce/plugins/instructure_icon_maker/svg/utils.js +3 -11
- package/es/rce/plugins/instructure_icon_maker/utils/IconMakerClose.js +4 -9
- package/es/rce/plugins/instructure_icon_maker/utils/IconMakerFormHasChanges.js +1 -15
- package/es/rce/plugins/instructure_icon_maker/utils/addIconMakerAttributes.js +3 -4
- package/es/rce/plugins/instructure_icon_maker/utils/iconValidation.js +2 -3
- package/es/rce/plugins/instructure_icon_maker/utils/iconsLabels.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/utils/useDebouncedValue.js +12 -13
- package/es/rce/plugins/instructure_image/ImageEmbedOptions.js +9 -31
- package/es/rce/plugins/instructure_image/ImageList/Image.js +8 -14
- package/es/rce/plugins/instructure_image/ImageList/index.js +8 -10
- package/es/rce/plugins/instructure_image/ImageOptionsTray/TrayController.js +9 -31
- package/es/rce/plugins/instructure_image/ImageOptionsTray/index.js +6 -19
- package/es/rce/plugins/instructure_image/Images/index.js +1 -3
- package/es/rce/plugins/instructure_image/clickCallback.js +1 -0
- package/es/rce/plugins/instructure_image/plugin.js +14 -20
- package/es/rce/plugins/instructure_links/clickCallback.js +1 -0
- package/es/rce/plugins/instructure_links/components/AccordionSection.js +8 -8
- package/es/rce/plugins/instructure_links/components/CollectionPanel.js +1 -3
- package/es/rce/plugins/instructure_links/components/Link.js +68 -84
- package/es/rce/plugins/instructure_links/components/LinkOptionsDialog/LinkOptionsDialogController.js +2 -23
- package/es/rce/plugins/instructure_links/components/LinkOptionsDialog/index.js +3 -6
- package/es/rce/plugins/instructure_links/components/LinkOptionsTray/LinkOptionsTrayController.js +3 -20
- package/es/rce/plugins/instructure_links/components/LinkOptionsTray/index.js +3 -14
- package/es/rce/plugins/instructure_links/components/LinkSet.js +32 -57
- package/es/rce/plugins/instructure_links/components/LinksPanel.js +22 -10
- package/es/rce/plugins/instructure_links/components/NavigationPanel.js +7 -9
- package/es/rce/plugins/instructure_links/components/NoResults.js +7 -14
- package/es/rce/plugins/instructure_links/plugin.js +23 -49
- package/es/rce/plugins/instructure_links/validateURL.js +81 -36
- package/es/rce/plugins/instructure_media_embed/clickCallback.js +5 -9
- package/es/rce/plugins/instructure_media_embed/components/Embed.js +7 -7
- package/es/rce/plugins/instructure_media_embed/plugin.js +7 -3
- package/es/rce/plugins/instructure_paste/pasteMenuCommand.js +1 -5
- package/es/rce/plugins/instructure_paste/plugin.js +29 -33
- package/es/rce/plugins/instructure_rce_external_tools/ExternalToolsEnv.js +31 -79
- package/es/rce/plugins/instructure_rce_external_tools/RceToolWrapper.js +24 -83
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +39 -69
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.js +1 -2
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogTray.js +1 -1
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog.js +5 -14
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionItem.js +1 -2
- package/es/rce/plugins/instructure_rce_external_tools/components/util/ExpandoText.js +1 -0
- package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.js +2 -1
- package/es/rce/plugins/instructure_rce_external_tools/constants.js +28 -0
- package/es/rce/plugins/instructure_rce_external_tools/dialog-helper.js +20 -6
- package/es/rce/plugins/instructure_rce_external_tools/helpers/tags.js +0 -2
- package/es/rce/plugins/instructure_rce_external_tools/jquery/jquery.dropdownList.js +129 -136
- package/es/rce/plugins/instructure_rce_external_tools/lti11-content-items/RceLti11ContentItem.js +110 -112
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/Lti13ContentItemJson.js +1 -0
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/RceLti13ContentItem.js +4 -21
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/BaseLinkContentItem.js +5 -19
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/HtmlFragmentContentItem.js +1 -6
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/ImageContentItem.js +1 -9
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/LinkContentItem.js +1 -1
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/ResourceLinkContentItem.js +3 -5
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/processEditorContentItems.js +23 -16
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/rceLti13ContentItemFromJson.js +3 -4
- package/es/rce/plugins/instructure_rce_external_tools/plugin.js +11 -20
- package/es/rce/plugins/instructure_rce_external_tools/util/addParentFrameContextToUrl.js +1 -1
- package/es/rce/plugins/instructure_rce_external_tools/util/externalToolsForToolbar.js +42 -0
- package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.js +6 -35
- package/es/rce/plugins/instructure_record/AudioOptionsTray/index.js +13 -17
- package/es/rce/plugins/instructure_record/MediaPanel/index.js +1 -9
- package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +16 -66
- package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +21 -35
- package/es/rce/plugins/instructure_record/clickCallback.js +32 -44
- package/es/rce/plugins/instructure_record/mediaTranslations.js +1 -0
- package/es/rce/plugins/instructure_record/plugin.js +11 -18
- package/es/rce/plugins/instructure_search_and_replace/clickCallback.js +4 -8
- package/es/rce/plugins/instructure_search_and_replace/components/FindReplaceTray.js +34 -51
- package/es/rce/plugins/instructure_search_and_replace/components/FindReplaceTrayController.js +12 -30
- package/es/rce/plugins/instructure_search_and_replace/getSelectionContext.js +2 -9
- package/es/rce/plugins/instructure_search_and_replace/plugin.js +2 -5
- package/es/rce/plugins/instructure_studio_media_options/plugin.js +1 -1
- package/es/rce/plugins/instructure_wordcount/clickCallback.js +5 -9
- package/es/rce/plugins/instructure_wordcount/components/WordCountModal.js +27 -37
- package/es/rce/plugins/instructure_wordcount/plugin.js +1 -0
- package/es/rce/plugins/instructure_wordcount/utils/countContent.js +4 -11
- package/es/rce/plugins/instructure_wordcount/utils/tableContent.js +6 -8
- package/es/rce/plugins/shared/CanvasContentTray.js +29 -63
- package/es/rce/plugins/shared/CheckerboardStyling.js +1 -1
- package/es/rce/plugins/shared/ColorInput.js +27 -39
- package/es/rce/plugins/shared/ConditionalTooltip.js +6 -6
- package/es/rce/plugins/shared/ContentSelection.js +29 -78
- package/es/rce/plugins/shared/DimensionUtils.js +3 -12
- package/es/rce/plugins/shared/DimensionsInput/DimensionInput.js +6 -6
- package/es/rce/plugins/shared/DimensionsInput/index.js +37 -15
- package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.js +5 -29
- package/es/rce/plugins/shared/ErrorBoundary.js +2 -5
- package/es/rce/plugins/shared/EventUtils.js +2 -4
- package/es/rce/plugins/shared/Filter.js +8 -38
- package/es/rce/plugins/shared/FixedContentTray.js +16 -17
- package/es/rce/plugins/shared/ImageCropper/DirectionRegion.js +4 -12
- package/es/rce/plugins/shared/ImageCropper/Modal.js +16 -20
- package/es/rce/plugins/shared/ImageCropper/Preview.js +18 -24
- package/es/rce/plugins/shared/ImageCropper/constants.js +1 -0
- package/es/rce/plugins/shared/ImageCropper/controls/CustomNumberInput.js +10 -14
- package/es/rce/plugins/shared/ImageCropper/controls/ResetControls.js +4 -4
- package/es/rce/plugins/shared/ImageCropper/controls/RotationControls.js +5 -15
- package/es/rce/plugins/shared/ImageCropper/controls/ShapeControls.js +8 -11
- package/es/rce/plugins/shared/ImageCropper/controls/ZoomControls.js +5 -16
- package/es/rce/plugins/shared/ImageCropper/controls/index.js +5 -5
- package/es/rce/plugins/shared/ImageCropper/controls/useDebouncedNumericValue.js +16 -31
- package/es/rce/plugins/shared/ImageCropper/controls/utils.js +1 -2
- package/es/rce/plugins/shared/ImageCropper/imageCropUtils.js +19 -31
- package/es/rce/plugins/shared/ImageCropper/index.js +1 -0
- package/es/rce/plugins/shared/ImageCropper/propTypes.js +1 -0
- package/es/rce/plugins/shared/ImageCropper/reducers/imageCropper.js +15 -14
- package/es/rce/plugins/shared/ImageCropper/shape.js +1 -0
- package/es/rce/plugins/shared/ImageCropper/svg/index.js +1 -2
- package/es/rce/plugins/shared/ImageCropper/svg/shape.js +5 -22
- package/es/rce/plugins/shared/ImageCropper/svg/utils.js +3 -4
- package/es/rce/plugins/shared/ImageCropper/useKeyMouseEvents.js +20 -50
- package/es/rce/plugins/shared/ImageCropper/useMouseWheel.js +8 -10
- package/es/rce/plugins/shared/ImageOptionsForm.js +18 -20
- package/es/rce/plugins/shared/LinkDisplay.js +9 -11
- package/es/rce/plugins/shared/PreviewIcon.js +9 -15
- package/es/rce/plugins/shared/Previewable.js +1 -0
- package/es/rce/plugins/shared/RceFileBrowser.js +7 -10
- package/es/rce/plugins/shared/StoreContext.js +9 -12
- package/es/rce/plugins/shared/StudioLtiSupportUtils.js +15 -12
- package/es/rce/plugins/shared/UnknownFileTypePanel.js +1 -0
- package/es/rce/plugins/shared/Upload/CanvasContentPanel.js +19 -25
- package/es/rce/plugins/shared/Upload/CategoryProcessor.js +2 -3
- package/es/rce/plugins/shared/Upload/ComputerPanel.js +19 -40
- package/es/rce/plugins/shared/Upload/PanelFilter.js +10 -20
- package/es/rce/plugins/shared/Upload/SvgCategoryProcessor.js +4 -3
- package/es/rce/plugins/shared/Upload/UploadFile.js +32 -38
- package/es/rce/plugins/shared/Upload/UploadFileModal.js +37 -59
- package/es/rce/plugins/shared/Upload/UrlPanel.js +5 -5
- package/es/rce/plugins/shared/Upload/UsageRightsSelectBox.js +25 -36
- package/es/rce/plugins/shared/Upload/doFileUpload.js +10 -13
- package/es/rce/plugins/shared/Upload/index.js +1 -0
- package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +8 -11
- package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +19 -40
- package/es/rce/plugins/shared/ai_tools/aiicons.js +3 -2
- package/es/rce/plugins/shared/ai_tools/index.js +1 -0
- package/es/rce/plugins/shared/buildDownloadUrl.js +0 -2
- package/es/rce/plugins/shared/canvasContentUtils.js +7 -11
- package/es/rce/plugins/shared/compressionUtils.js +18 -28
- package/es/rce/plugins/shared/dateUtils.js +1 -1
- package/es/rce/plugins/shared/do-fetch-api-effect/defaultFetchOptions.js +4 -2
- package/es/rce/plugins/shared/do-fetch-api-effect/doFetchApi.js +18 -24
- package/es/rce/plugins/shared/do-fetch-api-effect/get-cookie.js +1 -1
- package/es/rce/plugins/shared/do-fetch-api-effect/index.js +1 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/parse-link-header.js +6 -20
- package/es/rce/plugins/shared/do-fetch-api-effect/query-string-encoding.js +5 -3
- package/es/rce/plugins/shared/fileShape.js +4 -9
- package/es/rce/plugins/shared/fileTypeUtils.js +34 -47
- package/es/rce/plugins/shared/fileUtils.js +1 -2
- package/es/rce/plugins/shared/linkUtils.js +1 -16
- package/es/rce/plugins/shared/round.js +2 -2
- package/es/rce/plugins/shared/trayUtils.js +7 -3
- package/es/rce/plugins/shared/useDataUrl.js +13 -14
- package/es/rce/plugins/shared/useFilterSettings.js +3 -3
- package/es/rce/plugins/tinymce-a11y-checker/components/ColorField.js +4 -8
- package/es/rce/plugins/tinymce-a11y-checker/components/checker.js +12 -72
- package/es/rce/plugins/tinymce-a11y-checker/components/color-picker.js +1 -2
- package/es/rce/plugins/tinymce-a11y-checker/components/placeholder-svg.js +1 -0
- package/es/rce/plugins/tinymce-a11y-checker/components/pointer.js +1 -0
- package/es/rce/plugins/tinymce-a11y-checker/node-checker.js +2 -9
- package/es/rce/plugins/tinymce-a11y-checker/plugin.js +18 -24
- package/es/rce/plugins/tinymce-a11y-checker/rules/adjacent-links.js +3 -26
- package/es/rce/plugins/tinymce-a11y-checker/rules/headings-sequence.js +9 -38
- package/es/rce/plugins/tinymce-a11y-checker/rules/headings-start-at-h2.js +2 -7
- package/es/rce/plugins/tinymce-a11y-checker/rules/img-alt-filename.js +1 -2
- package/es/rce/plugins/tinymce-a11y-checker/rules/img-alt-length.js +1 -1
- package/es/rce/plugins/tinymce-a11y-checker/rules/img-alt.js +1 -2
- package/es/rce/plugins/tinymce-a11y-checker/rules/index.js +1 -0
- package/es/rce/plugins/tinymce-a11y-checker/rules/large-text-contrast.js +2 -6
- package/es/rce/plugins/tinymce-a11y-checker/rules/list-structure.js +5 -24
- package/es/rce/plugins/tinymce-a11y-checker/rules/paragraphs-for-headings.js +1 -3
- package/es/rce/plugins/tinymce-a11y-checker/rules/small-text-contrast.js +2 -8
- package/es/rce/plugins/tinymce-a11y-checker/rules/table-caption.js +1 -3
- package/es/rce/plugins/tinymce-a11y-checker/rules/table-header-scope.js +1 -2
- package/es/rce/plugins/tinymce-a11y-checker/rules/table-header.js +1 -9
- package/es/rce/plugins/tinymce-a11y-checker/utils/colors.js +1 -0
- package/es/rce/plugins/tinymce-a11y-checker/utils/describe.js +1 -7
- package/es/rce/plugins/tinymce-a11y-checker/utils/dom.js +3 -30
- package/es/rce/plugins/tinymce-a11y-checker/utils/indicate.js +18 -18
- package/es/rce/plugins/tinymce-a11y-checker/utils/rgb-hex.js +6 -12
- package/es/rce/plugins/tinymce-a11y-checker/utils/strings.js +1 -4
- package/es/rce/root.js +17 -16
- package/es/rce/sanitizePlugins.js +1 -3
- package/es/rce/style.js +1 -4
- package/es/rce/tinyRCE.js +14 -9
- package/es/rce/tinymce.oxide.content.min.css.js +1 -0
- package/es/rce/tinymce.oxide.skin.min.css.js +1 -0
- package/es/rce/transformContent.js +9 -11
- package/es/rce/types.js +1 -0
- package/es/rce/userOS.js +1 -1
- package/es/rce/wrapInitCb.js +50 -43
- package/es/rcs/api.js +100 -171
- package/es/rcs/buildError.js +8 -20
- package/es/rcs/fake.js +9 -20
- package/es/sidebar/actions/all_files.js +2 -0
- package/es/sidebar/actions/data.js +4 -7
- package/es/sidebar/actions/documents.js +19 -18
- package/es/sidebar/actions/files.js +21 -28
- package/es/sidebar/actions/filter.js +5 -5
- package/es/sidebar/actions/flickr.js +1 -1
- package/es/sidebar/actions/images.js +32 -37
- package/es/sidebar/actions/links.js +1 -0
- package/es/sidebar/actions/media.js +27 -28
- package/es/sidebar/actions/session.js +2 -5
- package/es/sidebar/actions/ui.js +1 -0
- package/es/sidebar/actions/upload.js +38 -74
- package/es/sidebar/containers/Sidebar.js +1 -2
- package/es/sidebar/containers/sidebarHandlers.js +9 -13
- package/es/sidebar/dragHtml.js +11 -5
- package/es/sidebar/reducers/all_files.js +5 -6
- package/es/sidebar/reducers/collection.js +12 -15
- package/es/sidebar/reducers/collections.js +6 -8
- package/es/sidebar/reducers/documents.js +7 -16
- package/es/sidebar/reducers/files.js +4 -6
- package/es/sidebar/reducers/filter.js +8 -23
- package/es/sidebar/reducers/flickr.js +10 -12
- package/es/sidebar/reducers/folder.js +16 -18
- package/es/sidebar/reducers/folders.js +4 -6
- package/es/sidebar/reducers/images.js +4 -16
- package/es/sidebar/reducers/index.js +3 -1
- package/es/sidebar/reducers/media.js +7 -16
- package/es/sidebar/reducers/newPageLinkExpanded.js +2 -5
- package/es/sidebar/reducers/noop.js +2 -2
- package/es/sidebar/reducers/rootFolderId.js +2 -5
- package/es/sidebar/reducers/session.js +4 -6
- package/es/sidebar/reducers/ui.js +6 -25
- package/es/sidebar/reducers/upload.js +16 -64
- package/es/sidebar/store/configureStore.js +1 -0
- package/es/sidebar/store/initialState.js +14 -26
- package/es/translations/locales/ab.js +1 -0
- package/es/translations/locales/ar.js +72 -8
- package/es/translations/locales/ca.js +72 -8
- package/es/translations/locales/cs.js +1 -0
- package/es/translations/locales/cs_CZ.js +1 -0
- package/es/translations/locales/cy.js +72 -8
- package/es/translations/locales/da-x-k12.js +72 -8
- package/es/translations/locales/da.js +72 -8
- package/es/translations/locales/da_DK.js +1 -0
- package/es/translations/locales/de.js +72 -8
- package/es/translations/locales/el.js +4 -0
- package/es/translations/locales/en-AU-x-unimelb.js +72 -8
- package/es/translations/locales/en-GB-x-ukhe.js +72 -8
- package/es/translations/locales/en.js +72 -8
- package/es/translations/locales/en_AU.js +72 -8
- package/es/translations/locales/en_CA.js +72 -8
- package/es/translations/locales/en_CY.js +72 -8
- package/es/translations/locales/en_GB.js +72 -8
- package/es/translations/locales/en_NZ.js +1 -0
- package/es/translations/locales/en_SE.js +1 -0
- package/es/translations/locales/en_US.js +1 -0
- package/es/translations/locales/es.js +72 -8
- package/es/translations/locales/es_ES.js +72 -8
- package/es/translations/locales/es_GT.js +1 -0
- package/es/translations/locales/fa_IR.js +7 -0
- package/es/translations/locales/fi.js +72 -8
- package/es/translations/locales/fr.js +72 -8
- package/es/translations/locales/fr_CA.js +73 -9
- package/es/translations/locales/ga.js +5 -13
- package/es/translations/locales/he.js +7 -0
- package/es/translations/locales/hi.js +72 -8
- package/es/translations/locales/ht.js +72 -8
- package/es/translations/locales/hu.js +7 -6
- package/es/translations/locales/hu_HU.js +1 -0
- package/es/translations/locales/hy.js +1 -0
- package/es/translations/locales/id.js +72 -8
- package/es/translations/locales/id_ID.js +1 -0
- package/es/translations/locales/is.js +72 -8
- package/es/translations/locales/it.js +72 -8
- package/es/translations/locales/ja.js +72 -8
- package/es/translations/locales/ko.js +1 -0
- package/es/translations/locales/ko_KR.js +1 -0
- package/es/translations/locales/lt.js +1 -0
- package/es/translations/locales/lt_LT.js +1 -0
- package/es/translations/locales/mi.js +72 -8
- package/es/translations/locales/mn_MN.js +1 -0
- package/es/translations/locales/ms.js +72 -8
- package/es/translations/locales/nb-x-k12.js +72 -8
- package/es/translations/locales/nb.js +72 -8
- package/es/translations/locales/nl.js +72 -8
- package/es/translations/locales/nl_NL.js +1 -0
- package/es/translations/locales/nn.js +7 -6
- package/es/translations/locales/pl.js +72 -8
- package/es/translations/locales/pt.js +72 -8
- package/es/translations/locales/pt_BR.js +72 -8
- package/es/translations/locales/ro.js +1 -0
- package/es/translations/locales/ru.js +72 -8
- package/es/translations/locales/se.js +1 -0
- package/es/translations/locales/sl.js +72 -8
- package/es/translations/locales/sv-x-k12.js +72 -8
- package/es/translations/locales/sv.js +72 -8
- package/es/translations/locales/sv_SE.js +1 -0
- package/es/translations/locales/tg.js +1 -0
- package/es/translations/locales/th.js +72 -8
- package/es/translations/locales/th_TH.js +1 -0
- package/es/translations/locales/tl_PH.js +1 -0
- package/es/translations/locales/tr.js +7 -0
- package/es/translations/locales/uk_UA.js +7 -0
- package/es/translations/locales/vi.js +72 -8
- package/es/translations/locales/vi_VN.js +1 -0
- package/es/translations/locales/zh-Hans.js +72 -8
- package/es/translations/locales/zh-Hant.js +72 -8
- package/es/translations/locales/zh.js +72 -8
- package/es/translations/locales/zh_HK.js +72 -8
- package/es/translations/locales/zh_TW.Big5.js +1 -0
- package/es/translations/locales/zh_TW.js +1 -0
- package/es/translations/tinymce/ar_SA.js +1 -0
- package/es/translations/tinymce/fi.js +1 -0
- package/es/translations/tinymce/ga.js +1 -0
- package/es/translations/tinymce/id.js +1 -0
- package/es/translations/tinymce/ru.js +1 -0
- package/es/translations/tinymce/ru_RU.js +1 -0
- package/es/translations/tinymce/sl.js +1 -0
- package/es/translations/tinymce/sr.js +1 -0
- package/es/translations/tinymce/th.js +1 -0
- package/es/translations/tinymce/uk_UA.js +1 -0
- package/es/translations/tinymce/vi_VN.js +1 -0
- package/es/util/TypedDict.js +4 -2
- package/es/util/elem-util.js +1 -1
- package/es/util/encrypted-storage.js +3 -13
- package/es/util/file-url-util.js +2 -7
- package/es/util/fullscreenHelpers.js +9 -9
- package/es/util/instui-icon-helper.js +4 -3
- package/es/util/loadingPlaceholder.js +39 -41
- package/es/util/simpleCache.js +1 -5
- package/es/util/string-util.js +1 -1
- package/es/util/textarea-editing-util.js +3 -7
- package/es/util/tinymce-plugin-util.js +0 -5
- package/es/util/url-util.js +20 -29
- package/eslint.config.js +250 -0
- package/jest.config.js +1 -1
- package/locales/en.json +190 -10
- package/package.json +78 -82
- package/scripts/build-canvas +2 -1
- package/scripts/build.js +4 -4
- package/scripts/installTranslations.js +7 -8
- package/testcafe/RCEWrapper.test.js +0 -1
- package/testcafe/StatusBar.test.js +0 -1
- package/testcafe/axe.test.js +3 -4
- package/testcafe/enhanceUserContent.test.js +0 -1
- package/tsconfig.json +21 -16
- package/{es/rce/__mocks__/styleMock.js → types/format-message-generate-id.d.ts} +6 -2
- package/{es/rce/plugins/shared/__mocks__/screenfull.js → types/js-beautify.d.ts} +4 -7
- package/.eslintrc +0 -45
- package/.prettierignore +0 -6
- package/es/rce/__mocks__/_mockCryptoEs.js +0 -124
- package/es/rce/__mocks__/tinymceReact.js +0 -55
- package/es/rce/plugins/tinymce-a11y-checker/rules/__mocks__/index.js +0 -53
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
1
|
/*
|
|
4
2
|
* Copyright (C) 2019 - present Instructure, Inc.
|
|
5
3
|
*
|
|
@@ -62,6 +60,7 @@
|
|
|
62
60
|
* href with the new URL. if the link text is updated, replace the link's
|
|
63
61
|
* content with the new plain text (deleting the image)
|
|
64
62
|
*/
|
|
63
|
+
|
|
65
64
|
import formatMessage from '../../../format-message';
|
|
66
65
|
import clickCallback from './clickCallback';
|
|
67
66
|
import bridge from '../../../bridge';
|
|
@@ -72,23 +71,17 @@ import tinymce from 'tinymce';
|
|
|
72
71
|
const trayController = new LinkOptionsTrayController();
|
|
73
72
|
const COURSE_PLUGIN_KEY = 'course_links';
|
|
74
73
|
const GROUP_PLUGIN_KEY = 'group_links';
|
|
75
|
-
|
|
76
74
|
function getCommandName(selectedNode) {
|
|
77
75
|
const isCourseLink = selectedNode.getAttribute('data-course-type');
|
|
78
76
|
return isCourseLink ? 'instructureTrayForCourseLinks' : 'instructureTrayToEditLink';
|
|
79
77
|
}
|
|
80
|
-
|
|
81
78
|
function selectedAnchorCount(ed) {
|
|
82
79
|
return ed.selection.getRng().cloneContents().querySelectorAll('a').length;
|
|
83
80
|
}
|
|
84
|
-
|
|
85
81
|
function getMenuItems(ed) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const contextType = (_ed$settings$canvas_r = ed.settings.canvas_rce_containing_context) === null || _ed$settings$canvas_r === void 0 ? void 0 : _ed$settings$canvas_r.type;
|
|
82
|
+
const contextType = ed.settings.canvas_rce_containing_context?.type;
|
|
89
83
|
const sel_anchors = ed.selection.isCollapsed() ? 0 : selectedAnchorCount(ed);
|
|
90
84
|
let items;
|
|
91
|
-
|
|
92
85
|
if (getAnchorElement(ed, ed.selection.getNode())) {
|
|
93
86
|
// cursor is on an anchor, edit or remove it
|
|
94
87
|
items = [{
|
|
@@ -103,7 +96,6 @@ function getMenuItems(ed) {
|
|
|
103
96
|
text: formatMessage('External Link'),
|
|
104
97
|
value: 'instructureLinkCreate'
|
|
105
98
|
}];
|
|
106
|
-
|
|
107
99
|
if (contextType === 'course') {
|
|
108
100
|
items.push({
|
|
109
101
|
text: formatMessage('Course Link'),
|
|
@@ -115,7 +107,6 @@ function getMenuItems(ed) {
|
|
|
115
107
|
value: 'instructure_group_links'
|
|
116
108
|
});
|
|
117
109
|
}
|
|
118
|
-
|
|
119
110
|
if (sel_anchors > 0) {
|
|
120
111
|
// selection contains anchor(s), so the user can remove them
|
|
121
112
|
items.push({
|
|
@@ -127,10 +118,8 @@ function getMenuItems(ed) {
|
|
|
127
118
|
});
|
|
128
119
|
}
|
|
129
120
|
}
|
|
130
|
-
|
|
131
121
|
return items;
|
|
132
122
|
}
|
|
133
|
-
|
|
134
123
|
function removeAnchorFromSelectedElement(ed) {
|
|
135
124
|
const selectedElem = ed.selection.getNode();
|
|
136
125
|
const anchorElem = getAnchorElement(ed, selectedElem);
|
|
@@ -138,7 +127,6 @@ function removeAnchorFromSelectedElement(ed) {
|
|
|
138
127
|
ed.undoManager.add();
|
|
139
128
|
ed.execCommand('Unlink');
|
|
140
129
|
}
|
|
141
|
-
|
|
142
130
|
function doMenuItem(ed, actionName) {
|
|
143
131
|
switch (actionName) {
|
|
144
132
|
case 'instructureTrayToEditLink':
|
|
@@ -146,30 +134,23 @@ function doMenuItem(ed, actionName) {
|
|
|
146
134
|
case 'instructureLinkCreate':
|
|
147
135
|
ed.execCommand(actionName);
|
|
148
136
|
break;
|
|
149
|
-
|
|
150
137
|
case 'instructureUnlink':
|
|
151
138
|
removeAnchorFromSelectedElement(ed);
|
|
152
139
|
break;
|
|
153
|
-
|
|
154
140
|
case 'instructureUnlinkAll':
|
|
155
141
|
ed.undoManager.add();
|
|
156
142
|
ed.execCommand('unlink');
|
|
157
143
|
break;
|
|
158
|
-
|
|
159
144
|
case 'instructure_course_links':
|
|
160
145
|
ed.focus(true); // activate the editor without changing focus
|
|
161
|
-
|
|
162
146
|
ed.execCommand('instructureTrayForLinks', false, COURSE_PLUGIN_KEY);
|
|
163
147
|
break;
|
|
164
|
-
|
|
165
148
|
case 'instructure_group_links':
|
|
166
149
|
ed.focus(true); // activate the editor without changing focus
|
|
167
|
-
|
|
168
150
|
ed.execCommand('instructureTrayForLinks', false, GROUP_PLUGIN_KEY);
|
|
169
151
|
break;
|
|
170
152
|
}
|
|
171
153
|
}
|
|
172
|
-
|
|
173
154
|
tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
174
155
|
// Register commands
|
|
175
156
|
ed.addCommand('instructureLinkCreate', () => clickCallback(ed, CREATE_LINK));
|
|
@@ -183,10 +164,12 @@ tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
|
183
164
|
ed.addCommand('instructureTrayForCourseLinks', () => {
|
|
184
165
|
ed.selection.select(ed.selection.getNode());
|
|
185
166
|
return bridge.showTrayForPlugin('course_link_edit', ed.id);
|
|
186
|
-
});
|
|
167
|
+
});
|
|
187
168
|
|
|
188
|
-
|
|
169
|
+
// Register shortcuts
|
|
170
|
+
ed.addShortcut('Meta+K', '', 'instructureLinkCreate');
|
|
189
171
|
|
|
172
|
+
// Register menu item
|
|
190
173
|
ed.ui.registry.addNestedMenuItem('instructure_links', {
|
|
191
174
|
text: formatMessage('Link'),
|
|
192
175
|
icon: 'link',
|
|
@@ -201,8 +184,9 @@ tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
|
201
184
|
}
|
|
202
185
|
};
|
|
203
186
|
})
|
|
204
|
-
});
|
|
187
|
+
});
|
|
205
188
|
|
|
189
|
+
// Register toolbar button
|
|
206
190
|
ed.ui.registry.addMenuButton('instructure_links', {
|
|
207
191
|
tooltip: formatMessage('Links'),
|
|
208
192
|
icon: 'link',
|
|
@@ -212,52 +196,43 @@ tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
|
212
196
|
value: item.value,
|
|
213
197
|
onAction: () => doMenuItem(ed, item.value)
|
|
214
198
|
}))),
|
|
215
|
-
|
|
216
199
|
onSetup(api) {
|
|
200
|
+
// @ts-expect-error
|
|
217
201
|
function handleNodeChange(e) {
|
|
218
|
-
if (e
|
|
202
|
+
if (e?.element) {
|
|
219
203
|
api.setActive(!!getAnchorElement(ed, e.element));
|
|
220
204
|
}
|
|
205
|
+
if (ed.selection) {
|
|
206
|
+
api.setDisabled(!isOKToLink(ed.selection.getContent()));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
221
209
|
|
|
222
|
-
|
|
223
|
-
} // if the user selects all the content w/in a link and deletes it via the keyboard
|
|
210
|
+
// if the user selects all the content w/in a link and deletes it via the keyboard
|
|
224
211
|
// make sure the surrounding <a> gets deleted too.
|
|
225
|
-
|
|
226
|
-
|
|
227
212
|
function deleteEmptyLink() {
|
|
228
213
|
let node = null;
|
|
229
|
-
|
|
230
214
|
if (ed.selection.getNode().tagName === 'A') {
|
|
231
215
|
node = ed.selection.getNode();
|
|
232
216
|
} else {
|
|
233
|
-
var _rng$endContainer$nex, _rng$nextSibling;
|
|
234
|
-
|
|
235
217
|
// Type checking is disabled here because the code below isn't type safe. The code below
|
|
236
218
|
// should be updated, specifically rng.endContainer.nextSibling?.tagName
|
|
237
219
|
const rng = ed.selection.getRng();
|
|
238
|
-
|
|
239
|
-
if (rng.commonAncestorContainer === rng.endContainer && ((_rng$endContainer$nex = rng.endContainer.nextSibling) === null || _rng$endContainer$nex === void 0 ? void 0 : _rng$endContainer$nex.tagName) === 'A') {
|
|
220
|
+
if (rng.commonAncestorContainer === rng.endContainer && rng.endContainer.nextSibling?.tagName === 'A') {
|
|
240
221
|
node = rng.endContainer.nextSibling;
|
|
241
|
-
} else if (
|
|
222
|
+
} else if (rng.nextSibling?.tagName === 'A') {
|
|
242
223
|
node = rng.nextSibling;
|
|
243
224
|
}
|
|
244
225
|
}
|
|
245
|
-
|
|
246
226
|
if (node) {
|
|
247
|
-
var _node$textContent;
|
|
248
|
-
|
|
249
227
|
if (node.firstElementChild) {
|
|
250
228
|
return;
|
|
251
229
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if ((txt === null || txt === void 0 ? void 0 : txt.length) === 0) {
|
|
230
|
+
const txt = node.textContent?.trim();
|
|
231
|
+
if (txt?.length === 0) {
|
|
256
232
|
ed.execCommand('Unlink');
|
|
257
233
|
}
|
|
258
234
|
}
|
|
259
235
|
}
|
|
260
|
-
|
|
261
236
|
setTimeout(handleNodeChange, 0, null);
|
|
262
237
|
ed.on('NodeChange', handleNodeChange);
|
|
263
238
|
ed.on('Change', deleteEmptyLink);
|
|
@@ -266,14 +241,14 @@ tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
|
266
241
|
ed.off('Change', deleteEmptyLink);
|
|
267
242
|
};
|
|
268
243
|
}
|
|
244
|
+
});
|
|
269
245
|
|
|
270
|
-
|
|
271
|
-
|
|
246
|
+
// the context toolbar buttons
|
|
272
247
|
ed.ui.registry.addButton('instructure-link-options', {
|
|
273
|
-
onAction(
|
|
248
|
+
onAction(/* buttonApi */
|
|
249
|
+
) {
|
|
274
250
|
ed.execCommand(getCommandName(ed.selection.getNode()), false, ed);
|
|
275
251
|
},
|
|
276
|
-
|
|
277
252
|
text: formatMessage('Link Options'),
|
|
278
253
|
tooltip: formatMessage('Show link options')
|
|
279
254
|
});
|
|
@@ -282,7 +257,6 @@ tinymce.PluginManager.add('instructure_links', function (ed) {
|
|
|
282
257
|
onAction() {
|
|
283
258
|
removeAnchorFromSelectedElement(ed);
|
|
284
259
|
},
|
|
285
|
-
|
|
286
260
|
text: remButtonLabel
|
|
287
261
|
});
|
|
288
262
|
ed.ui.registry.addContextToolbar('instructure-link-toolbar', {
|
|
@@ -15,56 +15,101 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License along
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
import { parse } from 'url';
|
|
19
|
-
import formatMessage from '../../../format-message'; // keep in sync with the protocols permitted for <a href>
|
|
20
|
-
// as listed in gems/canvas_sanitize/lib/canvas_sanitize/canvas_sanitize.rb
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
// return true if valid
|
|
24
|
-
// return false if not valid yet, but incomplete
|
|
25
|
-
// throw an Error if invalid
|
|
19
|
+
import formatMessage from '../../../format-message';
|
|
26
20
|
|
|
21
|
+
// Keep in sync with the protocols permitted for <a href>
|
|
22
|
+
// as listed in gems/canvas_sanitize/lib/canvas_sanitize/canvas_sanitize.rb
|
|
23
|
+
const allowed_protocols = ['ftp:', 'http:', 'https:', 'mailto:', 'tel:', 'skype:'];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Weakly validate a URL
|
|
27
|
+
* @param {string} url URL to validate
|
|
28
|
+
* @returns {boolean} true if valid, false if not valid yet, but incomplete, throws if invalid
|
|
29
|
+
*/
|
|
27
30
|
export default function validateURL(url) {
|
|
28
31
|
const href = url.trim();
|
|
29
|
-
const parsed = parse(href, false, true);
|
|
30
|
-
const protocol = parsed.protocol;
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Handle special cases for partial URLs
|
|
34
|
+
if (href === '' || href === 'mailto:' || href === 'tel:' || href === 'skype:') {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (/^\/\/$/.test(href)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
// Handle URLs starting with :// (invalid protocol)
|
|
42
|
+
if (href.startsWith('://')) {
|
|
36
43
|
throw new Error(formatMessage('Protocol must be ftp, http, https, mailto, skype, tel or may be omitted'));
|
|
37
44
|
}
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}));
|
|
48
|
-
} // ftp, http, https require ://anything
|
|
49
|
-
|
|
46
|
+
// For URLs with protocols, we can use the URL constructor directly
|
|
47
|
+
if (/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(href)) {
|
|
48
|
+
const protocol = href.substring(0, href.indexOf(':') + 1);
|
|
49
|
+
if (!allowed_protocols.includes(protocol)) {
|
|
50
|
+
throw new Error(formatMessage('{p} is not a valid protocol.', {
|
|
51
|
+
p: protocol.slice(0, -1)
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
// For absolute URLs with protocols that require //, validate the format
|
|
56
|
+
if (['http:', 'https:', 'ftp:'].includes(protocol) && !href.startsWith(protocol + '//')) {
|
|
57
|
+
throw new Error(formatMessage('Invalid URL'));
|
|
58
|
+
}
|
|
55
59
|
|
|
60
|
+
// Special handling for mailto:, tel:, and skype: URLs
|
|
61
|
+
if (['mailto:', 'tel:', 'skype:'].includes(protocol)) {
|
|
62
|
+
// Consider protocol:// as incomplete for these protocols
|
|
63
|
+
if (href === protocol + '//' || href === protocol + '///') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return href.length > protocol.length;
|
|
67
|
+
}
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
// Handle partial URLs
|
|
70
|
+
if (href === protocol || href === protocol + '/' || href === protocol + '//') {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
60
73
|
|
|
74
|
+
// Try constructing the URL to validate the format
|
|
75
|
+
try {
|
|
76
|
+
if (href.includes('//')) {
|
|
77
|
+
new URL(href);
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
} catch {
|
|
81
|
+
// If URL construction fails but we have more than just protocol://, consider it valid
|
|
82
|
+
// This allows for test URLs like ftp://host:port/path
|
|
83
|
+
return href.length > protocol.length + 2;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
// Handle protocol-relative URLs
|
|
88
|
+
if (href.startsWith('//')) {
|
|
89
|
+
if (href === '//' || href === '///') {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
new URL('http:' + href);
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
// If URL construction fails but we have more than just //, consider it valid
|
|
97
|
+
return href.length > 2;
|
|
98
|
+
}
|
|
64
99
|
}
|
|
65
100
|
|
|
66
|
-
|
|
101
|
+
// Handle relative paths
|
|
102
|
+
return true;
|
|
103
|
+
} catch (e) {
|
|
104
|
+
if (e instanceof Error) {
|
|
105
|
+
if (e.message.includes('Invalid URL')) {
|
|
106
|
+
if (href.match(/^(https?|ftp):\/?\/?$/)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
throw new Error(formatMessage('Invalid URL'));
|
|
110
|
+
}
|
|
111
|
+
throw e;
|
|
112
|
+
}
|
|
113
|
+
throw e;
|
|
67
114
|
}
|
|
68
|
-
|
|
69
|
-
return true;
|
|
70
115
|
}
|
|
@@ -15,32 +15,28 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License along
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
|
|
18
19
|
import React from 'react';
|
|
19
20
|
import ReactDOM from 'react-dom';
|
|
20
21
|
import Bridge from '../../../bridge';
|
|
21
22
|
export default function (ed, document) {
|
|
22
|
-
return import('./components/Embed').then(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} = _ref;
|
|
23
|
+
return import('./components/Embed').then(({
|
|
24
|
+
Embed
|
|
25
|
+
}) => {
|
|
26
26
|
let container = document.querySelector('.canvas-rce-embed-container');
|
|
27
|
-
|
|
28
27
|
if (!container) {
|
|
29
28
|
container = document.createElement('div');
|
|
30
29
|
container.className = 'canvas-rce-embed-container';
|
|
31
30
|
document.body.appendChild(container);
|
|
32
31
|
}
|
|
33
|
-
|
|
34
32
|
const handleDismiss = () => {
|
|
35
33
|
ReactDOM.unmountComponentAtNode(container);
|
|
36
34
|
ed.focus(false);
|
|
37
35
|
};
|
|
38
|
-
|
|
39
36
|
const handleEmbedCode = embedCode => {
|
|
40
37
|
Bridge.insertEmbedCode(embedCode);
|
|
41
38
|
};
|
|
42
|
-
|
|
43
|
-
ReactDOM.render( /*#__PURE__*/React.createElement(Embed, {
|
|
39
|
+
ReactDOM.render(/*#__PURE__*/React.createElement(Embed, {
|
|
44
40
|
onSubmit: handleEmbedCode,
|
|
45
41
|
onDismiss: handleDismiss
|
|
46
42
|
}), container);
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License along
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
|
|
18
19
|
import React, { useState } from 'react';
|
|
19
20
|
import { Modal } from '@instructure/ui-modal';
|
|
20
21
|
import formatMessage from '../../../../format-message';
|
|
@@ -22,17 +23,16 @@ import { Button, CloseButton } from '@instructure/ui-buttons';
|
|
|
22
23
|
import { Heading } from '@instructure/ui-heading';
|
|
23
24
|
import { func } from 'prop-types';
|
|
24
25
|
import { TextArea } from '@instructure/ui-text-area';
|
|
25
|
-
import {
|
|
26
|
-
export function Embed(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} = _ref;
|
|
26
|
+
import { instuiPopupMountNodeFn } from '../../../../util/fullscreenHelpers';
|
|
27
|
+
export function Embed({
|
|
28
|
+
onSubmit,
|
|
29
|
+
onDismiss
|
|
30
|
+
}) {
|
|
31
31
|
const [embedCode, setEmbedCode] = useState('');
|
|
32
32
|
return /*#__PURE__*/React.createElement(Modal, {
|
|
33
33
|
"data-mce-component": true,
|
|
34
34
|
label: formatMessage('Embed'),
|
|
35
|
-
mountNode:
|
|
35
|
+
mountNode: instuiPopupMountNodeFn,
|
|
36
36
|
size: "medium",
|
|
37
37
|
onDismiss: onDismiss,
|
|
38
38
|
open: true,
|
|
@@ -15,19 +15,23 @@
|
|
|
15
15
|
* You should have received a copy of the GNU Affero General Public License along
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
|
|
18
19
|
import clickCallback from './clickCallback';
|
|
19
20
|
import formatMessage from '../../../format-message';
|
|
20
|
-
import tinymce from 'tinymce';
|
|
21
|
+
import tinymce from 'tinymce';
|
|
21
22
|
|
|
23
|
+
// Register plugin
|
|
22
24
|
tinymce.PluginManager.add('instructure_media_embed', function (ed) {
|
|
23
|
-
ed.addCommand('instructureMediaEmbed', () => clickCallback(ed, document));
|
|
25
|
+
ed.addCommand('instructureMediaEmbed', () => clickCallback(ed, document));
|
|
24
26
|
|
|
27
|
+
// Register menu item
|
|
25
28
|
ed.ui.registry.addMenuItem('instructure_media_embed', {
|
|
26
29
|
text: formatMessage('Embed'),
|
|
27
30
|
icon: 'embed',
|
|
28
31
|
onAction: () => ed.execCommand('instructureMediaEmbed')
|
|
29
|
-
});
|
|
32
|
+
});
|
|
30
33
|
|
|
34
|
+
// Register toolbar button
|
|
31
35
|
ed.ui.registry.addButton('instructure_media_embed', {
|
|
32
36
|
tooltip: formatMessage('Embed'),
|
|
33
37
|
icon: 'embed',
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* because figuring this stuff out wasn't trivial and
|
|
24
24
|
* I didn't want to lose it.
|
|
25
25
|
********************************************************* */
|
|
26
|
+
|
|
26
27
|
import formatMessage from '../../../format-message';
|
|
27
28
|
import { showFlashAlert } from '../../../common/FlashAlert';
|
|
28
29
|
export function initPasteMenuCommand(ed, handlePasteOrDrop) {
|
|
@@ -39,7 +40,6 @@ export function initPasteMenuCommand(ed, handlePasteOrDrop) {
|
|
|
39
40
|
text: formatMessage('Paste'),
|
|
40
41
|
icon: 'paste',
|
|
41
42
|
onAction: () => ed.execCommand('instructurePaste'),
|
|
42
|
-
|
|
43
43
|
onSetup(_api) {
|
|
44
44
|
// If I add the shortcut, then it overwrites the browsers
|
|
45
45
|
// built-in keyboard shortcut for paste. we don't want that
|
|
@@ -47,15 +47,12 @@ export function initPasteMenuCommand(ed, handlePasteOrDrop) {
|
|
|
47
47
|
ed.execCommand('instructurePaste');
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
|
|
51
50
|
});
|
|
52
|
-
|
|
53
51
|
async function handlePasteMenuCommand() {
|
|
54
52
|
try {
|
|
55
53
|
const cbitems = await window.navigator.clipboard.read();
|
|
56
54
|
const cbitem = cbitems[0];
|
|
57
55
|
const imageType = cbitem.types.find(t => /^image\//.test(t));
|
|
58
|
-
|
|
59
56
|
if (imageType) {
|
|
60
57
|
const blob = await cbitem.getType(imageType);
|
|
61
58
|
const file = new File([blob], imageType.replace('/', '.'), {
|
|
@@ -92,7 +89,6 @@ export function initPasteMenuCommand(ed, handlePasteOrDrop) {
|
|
|
92
89
|
});
|
|
93
90
|
} else {
|
|
94
91
|
const textType = cbitem.types.find(t => /^text\//.test(t));
|
|
95
|
-
|
|
96
92
|
if (textType) {
|
|
97
93
|
const blob = await cbitem.getType(textType);
|
|
98
94
|
const text = await blob.text();
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
1
|
/*
|
|
4
2
|
* Copyright (C) 2022 - present Instructure, Inc.
|
|
5
3
|
*
|
|
@@ -17,6 +15,7 @@
|
|
|
17
15
|
* You should have received a copy of the GNU Affero General Public License along
|
|
18
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19
17
|
*/
|
|
18
|
+
|
|
20
19
|
import tinymce from 'tinymce';
|
|
21
20
|
import bridge from '../../../bridge';
|
|
22
21
|
import configureStore from '../../../sidebar/store/configureStore';
|
|
@@ -34,7 +33,9 @@ const config = {
|
|
|
34
33
|
session: null,
|
|
35
34
|
// null: we haven't gotten it yet, false: we don't need it
|
|
36
35
|
sessionPromise: null
|
|
37
|
-
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// when UploadFile renders
|
|
38
39
|
// <StoreProvider {...trayProps}>
|
|
39
40
|
// {contentProps => {
|
|
40
41
|
// return (
|
|
@@ -43,18 +44,18 @@ const config = {
|
|
|
43
44
|
// (We don't seem to have a way to grab an existing store)
|
|
44
45
|
// So the configureStore and getSession logic gets repeated here for the
|
|
45
46
|
// automatic file upload when pasting or dropping a file on the RCE
|
|
46
|
-
|
|
47
|
+
// @ts-expect-error
|
|
47
48
|
function initStore(initProps) {
|
|
48
49
|
if (config.store === null) {
|
|
49
50
|
config.store = configureStore(initProps);
|
|
50
51
|
}
|
|
51
|
-
|
|
52
52
|
if (config.session === null) {
|
|
53
53
|
if (initProps.host && initProps.jwt) {
|
|
54
54
|
config.sessionPromise = getSession(config.store.dispatch, config.store.getState).then(() => {
|
|
55
55
|
config.session = config.store.getState().session;
|
|
56
|
-
})
|
|
57
|
-
|
|
56
|
+
})
|
|
57
|
+
// @ts-expect-error
|
|
58
|
+
.catch(_err => {
|
|
58
59
|
console.error('The Paste plugin failed to get canvas session data.');
|
|
59
60
|
});
|
|
60
61
|
} else {
|
|
@@ -63,12 +64,11 @@ function initStore(initProps) {
|
|
|
63
64
|
config.sessionPromise = Promise.resolve();
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
|
-
|
|
67
67
|
return config.store;
|
|
68
68
|
}
|
|
69
|
-
|
|
70
69
|
tinymce.PluginManager.add('instructure_paste', function (editor) {
|
|
71
70
|
const store = initStore(bridge.trayProps.get(editor));
|
|
71
|
+
|
|
72
72
|
/**
|
|
73
73
|
* Starts the file upload (and insertion) process for the given file.
|
|
74
74
|
*
|
|
@@ -76,13 +76,11 @@ tinymce.PluginManager.add('instructure_paste', function (editor) {
|
|
|
76
76
|
*
|
|
77
77
|
* @returns a promise that resolves when the user has made their choice about uploading the file
|
|
78
78
|
*/
|
|
79
|
-
|
|
80
79
|
async function requestFileInsertion(file) {
|
|
81
80
|
// it's very doubtful that we won't have retrieved the session data yet,
|
|
82
81
|
// since it takes a while for the RCE to initialize, but if we haven't
|
|
83
82
|
// wait until we do to carry on and finish pasting.
|
|
84
83
|
await config.sessionPromise;
|
|
85
|
-
|
|
86
84
|
if (config.session === null) {
|
|
87
85
|
// we failed to get the session and don't know if usage rights are required in this course|group
|
|
88
86
|
// In all probability, the file upload will fail too, but I feel like we have to do something here.
|
|
@@ -90,12 +88,11 @@ tinymce.PluginManager.add('instructure_paste', function (editor) {
|
|
|
90
88
|
message: formatMessage('If Usage Rights are required, the file will not publish until enabled in the Files page.'),
|
|
91
89
|
type: 'info'
|
|
92
90
|
});
|
|
93
|
-
}
|
|
94
|
-
// on the user to store it. Only Group and Course.
|
|
95
|
-
|
|
91
|
+
}
|
|
96
92
|
|
|
93
|
+
// even though usage rights might be required by the course, canvas has no place
|
|
94
|
+
// on the user to store it. Only Group and Course.
|
|
97
95
|
const requiresUsageRights = config.session.usageRightsRequired && /course|group/.test(bridge.trayProps.get(editor).contextType);
|
|
98
|
-
|
|
99
96
|
if (requiresUsageRights) {
|
|
100
97
|
return doFileUpload(editor, document, {
|
|
101
98
|
accept: file.type,
|
|
@@ -114,61 +111,60 @@ tinymce.PluginManager.add('instructure_paste', function (editor) {
|
|
|
114
111
|
domObject: file
|
|
115
112
|
};
|
|
116
113
|
let tabContext = 'documents';
|
|
117
|
-
|
|
118
114
|
if (isImage(file.type)) {
|
|
119
115
|
tabContext = 'images';
|
|
120
116
|
} else if (isAudioOrVideo(file.type)) {
|
|
121
117
|
tabContext = 'media';
|
|
122
118
|
}
|
|
123
|
-
|
|
124
119
|
store.dispatch(uploadToMediaFolder(tabContext, fileMetaProps));
|
|
125
120
|
return 'submitted';
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
|
-
|
|
129
123
|
async function handlePasteOrDrop(event) {
|
|
130
|
-
var _bridge$activeEditor, _bridge$activeEditor$, _editor$rceWrapper;
|
|
131
|
-
|
|
132
124
|
const isPaste = event.type === 'paste';
|
|
133
125
|
const dataTransfer = isPaste ? event.clipboardData : event.dataTransfer;
|
|
134
|
-
const files = Array.from(
|
|
135
|
-
const types =
|
|
136
|
-
const isAudioVideoDisabled =
|
|
126
|
+
const files = Array.from(dataTransfer?.files || []);
|
|
127
|
+
const types = dataTransfer?.types || [];
|
|
128
|
+
const isAudioVideoDisabled = bridge.activeEditor()?.props?.instRecordDisabled;
|
|
129
|
+
|
|
130
|
+
// delegate to tiny if there aren't any files to handle
|
|
131
|
+
if (!types.includes('Files')) return;
|
|
137
132
|
|
|
138
|
-
|
|
133
|
+
// delegate to tiny if there is Microsoft Word content, because it may contain an image
|
|
139
134
|
// rendering of the content and we don't want to incorrectly paste the image
|
|
140
135
|
// instead of the actual rich content, which TinyMCE has special handing for
|
|
136
|
+
if (isMicrosoftWordContentInEvent(event)) return;
|
|
141
137
|
|
|
142
|
-
|
|
138
|
+
// we're pasting file(s), prevent the default tinymce pasting behavior
|
|
139
|
+
event.preventDefault();
|
|
143
140
|
|
|
144
|
-
|
|
141
|
+
// Ensure the editor has focus, because downstream code requires that it does, and drag-n-drop
|
|
145
142
|
// events can be started when the editor doesn't have focus.
|
|
143
|
+
if (!editor.hasFocus()) editor.rceWrapper?.focus();
|
|
146
144
|
|
|
147
|
-
|
|
145
|
+
// Checking if we've encountered an issue with file processing for paste events in the browser
|
|
148
146
|
// Specifically implementing due to this bug in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1699743
|
|
149
147
|
// However, there could be other issues that cause this condition so it's a nice safety net regardless
|
|
150
|
-
|
|
151
148
|
if (isPaste && files.some(file => file.size === 0)) {
|
|
149
|
+
// @ts-expect-error
|
|
152
150
|
showFlashAlert({
|
|
153
151
|
message: formatMessage('One or more files failed to paste. Please try uploading or dragging and dropping files.'),
|
|
154
152
|
type: 'error'
|
|
155
153
|
});
|
|
156
154
|
return;
|
|
157
155
|
}
|
|
158
|
-
|
|
159
156
|
for (const file of files) {
|
|
160
157
|
if (isAudioVideoDisabled && isAudioOrVideo(file.type)) {
|
|
161
158
|
// Skip audio and video files when disabled
|
|
162
159
|
continue;
|
|
163
|
-
}
|
|
164
|
-
// to show a dialog for each file without them conflicting.
|
|
165
|
-
// eslint-disable-next-line no-await-in-loop
|
|
160
|
+
}
|
|
166
161
|
|
|
162
|
+
// This will finish once the dialog is closed, if one was created, putting this in a loop allows us
|
|
163
|
+
// to show a dialog for each file without them conflicting.
|
|
167
164
|
|
|
168
165
|
await requestFileInsertion(file);
|
|
169
166
|
}
|
|
170
167
|
}
|
|
171
|
-
|
|
172
168
|
editor.on('paste', handlePasteOrDrop);
|
|
173
169
|
editor.on('drop', handlePasteOrDrop);
|
|
174
170
|
});
|