@instructure/canvas-rce 5.13.2 → 5.13.5
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 +24 -0
- package/es/bridge/Bridge.js +0 -4
- package/es/defaultTinymceConfig.js +1 -1
- package/es/index.js +2 -0
- package/es/rce/RCE.js +3 -1
- package/es/rce/RCEVariants.js +121 -0
- package/es/rce/RCEWrapper.js +96 -47
- package/es/rce/RCEWrapperProps.js +5 -2
- package/es/rce/StatusBar.js +67 -17
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/Footer.js +1 -0
- package/es/rce/plugins/instructure_icon_maker/components/IconMakerTray.js +6 -1
- package/es/rce/plugins/instructure_rce_external_tools/RceToolWrapper.js +9 -9
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +25 -3
- package/es/rce/plugins/instructure_rce_external_tools/plugin.js +4 -1
- package/es/rce/plugins/shared/CanvasContentTray.js +6 -158
- package/es/rce/plugins/shared/Filter.js +0 -17
- package/es/rce/plugins/shared/FixedContentTray.js +7 -4
- package/es/rce/plugins/shared/ImageOptionsForm.js +3 -2
- package/es/rce/plugins/shared/Upload/CanvasContentPanel.js +160 -0
- package/es/rce/plugins/shared/Upload/ComputerPanel.js +1 -0
- package/es/rce/plugins/shared/Upload/PanelFilter.js +144 -0
- package/es/rce/plugins/shared/Upload/UploadFile.js +10 -2
- package/es/rce/plugins/shared/Upload/UploadFileModal.js +47 -11
- package/es/rce/plugins/shared/Upload/UsageRightsSelectBox.js +20 -20
- package/es/rce/plugins/shared/Upload/index.js +19 -0
- package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +70 -0
- package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +510 -0
- package/es/rce/plugins/shared/ai_tools/aiicons.js +59 -0
- package/es/rce/plugins/shared/ai_tools/index.js +20 -0
- package/es/rce/plugins/shared/canvasContentUtils.js +190 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/defaultFetchOptions.js +31 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/doFetchApi.js +85 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/get-cookie.js +29 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/index.js +22 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/parse-link-header.js +116 -0
- package/es/rce/plugins/shared/do-fetch-api-effect/query-string-encoding.js +51 -0
- package/es/rce/plugins/shared/useFilterSettings.js +35 -0
- package/es/sidebar/actions/upload.js +5 -2
- package/es/translations/locales/ar.js +64 -1
- package/es/translations/locales/ca.js +65 -2
- package/es/translations/locales/cy.js +64 -1
- package/es/translations/locales/da-x-k12.js +65 -2
- package/es/translations/locales/da.js +65 -2
- package/es/translations/locales/de.js +65 -2
- package/es/translations/locales/el.js +9 -0
- package/es/translations/locales/en-AU-x-unimelb.js +65 -2
- package/es/translations/locales/en-GB-x-ukhe.js +65 -2
- package/es/translations/locales/en.js +65 -2
- package/es/translations/locales/en_AU.js +65 -2
- package/es/translations/locales/en_CA.js +65 -2
- package/es/translations/locales/en_CY.js +65 -2
- package/es/translations/locales/en_GB.js +65 -2
- package/es/translations/locales/es.js +64 -1
- package/es/translations/locales/es_ES.js +64 -1
- package/es/translations/locales/fa_IR.js +9 -0
- package/es/translations/locales/fi.js +64 -1
- package/es/translations/locales/fr.js +65 -2
- package/es/translations/locales/fr_CA.js +65 -2
- package/es/translations/locales/ga.js +62 -2
- package/es/translations/locales/he.js +9 -0
- package/es/translations/locales/hi.js +119 -2
- package/es/translations/locales/ht.js +65 -2
- package/es/translations/locales/hu.js +15 -3
- package/es/translations/locales/hy.js +9 -0
- package/es/translations/locales/id.js +65 -2
- package/es/translations/locales/is.js +65 -2
- package/es/translations/locales/it.js +65 -2
- package/es/translations/locales/ja.js +65 -2
- package/es/translations/locales/ko.js +3 -0
- package/es/translations/locales/mi.js +65 -2
- package/es/translations/locales/ms.js +64 -1
- package/es/translations/locales/nb-x-k12.js +65 -2
- package/es/translations/locales/nb.js +65 -2
- package/es/translations/locales/nl.js +65 -2
- package/es/translations/locales/nn.js +15 -3
- package/es/translations/locales/pl.js +64 -1
- package/es/translations/locales/pt.js +64 -1
- package/es/translations/locales/pt_BR.js +65 -2
- package/es/translations/locales/ru.js +64 -1
- package/es/translations/locales/sl.js +65 -2
- package/es/translations/locales/sv-x-k12.js +65 -2
- package/es/translations/locales/sv.js +65 -2
- package/es/translations/locales/th.js +64 -1
- package/es/translations/locales/tr.js +9 -0
- package/es/translations/locales/uk_UA.js +9 -0
- package/es/translations/locales/vi.js +64 -1
- package/es/translations/locales/zh-Hans.js +64 -1
- package/es/translations/locales/zh-Hant.js +65 -2
- package/es/translations/locales/zh.js +64 -1
- package/es/translations/locales/zh_HK.js +65 -2
- package/es/translations/tinymce/ar_SA.js +4 -0
- package/es/translations/tinymce/bg_BG.js +4 -0
- package/es/translations/tinymce/ca.js +4 -0
- package/es/translations/tinymce/cs.js +4 -0
- package/es/translations/tinymce/cy.js +4 -0
- package/es/translations/tinymce/da.js +4 -0
- package/es/translations/tinymce/de.js +4 -0
- package/es/translations/tinymce/el.js +4 -0
- package/es/translations/tinymce/es.js +4 -0
- package/es/translations/tinymce/fa_IR.js +4 -0
- package/es/translations/tinymce/fr_FR.js +4 -0
- package/es/translations/tinymce/ga.js +4 -0
- package/es/translations/tinymce/he_IL.js +4 -0
- package/es/translations/tinymce/hu_HU.js +4 -0
- package/es/translations/tinymce/hy.js +4 -0
- package/es/translations/tinymce/id.js +4 -0
- package/es/translations/tinymce/it.js +4 -0
- package/es/translations/tinymce/ja.js +4 -0
- package/es/translations/tinymce/ko_KR.js +4 -0
- package/es/translations/tinymce/nb_NO.js +4 -0
- package/es/translations/tinymce/nl.js +4 -0
- package/es/translations/tinymce/pl.js +4 -0
- package/es/translations/tinymce/pt_BR.js +4 -0
- package/es/translations/tinymce/pt_PT.js +4 -0
- package/es/translations/tinymce/ro.js +4 -0
- package/es/translations/tinymce/ru.js +4 -0
- package/es/translations/tinymce/ru_RU.js +5 -1
- package/es/translations/tinymce/sl.js +4 -0
- package/es/translations/tinymce/sr.js +4 -0
- package/es/translations/tinymce/sv_SE.js +4 -0
- package/es/translations/tinymce/th.js +5 -1
- package/es/translations/tinymce/tr_TR.js +4 -0
- package/es/translations/tinymce/uk_UA.js +4 -0
- package/es/translations/tinymce/vi_VN.js +4 -0
- package/es/translations/tinymce/zh_CN.js +4 -0
- package/es/translations/tinymce/zh_TW.js +4 -0
- package/jest/jest-setup.js +1 -0
- package/package.json +1 -1
|
@@ -160,7 +160,9 @@ export function IconMakerTray(_ref) {
|
|
|
160
160
|
|
|
161
161
|
const onClose = event => {
|
|
162
162
|
if (shouldIgnoreClose(event === null || event === void 0 ? void 0 : event.target, editor === null || editor === void 0 ? void 0 : editor.id)) return;
|
|
163
|
-
if ((statusRef === null || statusRef === void 0 ? void 0 : statusRef.current) === statuses.LOADING) return; //
|
|
163
|
+
if ((statusRef === null || statusRef === void 0 ? void 0 : statusRef.current) === statuses.LOADING) return; // Uploading an image creates a modal on the page. If that modal is open, we don't want to close the tray
|
|
164
|
+
|
|
165
|
+
if (!!hasOpenModal()) return; // RCE already uses browser's confirm dialog for unsaved changes
|
|
164
166
|
// Its use here in the Icon Maker tray keeps that consistency
|
|
165
167
|
// eslint-disable-next-line no-restricted-globals, no-alert
|
|
166
168
|
|
|
@@ -171,6 +173,8 @@ export function IconMakerTray(_ref) {
|
|
|
171
173
|
setIsOpen(false);
|
|
172
174
|
};
|
|
173
175
|
|
|
176
|
+
const hasOpenModal = () => document.querySelector('[data-cid="Modal"]');
|
|
177
|
+
|
|
174
178
|
const isLoading = () => status === statuses.LOADING;
|
|
175
179
|
|
|
176
180
|
const onKeyDown = event => {
|
|
@@ -304,6 +308,7 @@ export function IconMakerTray(_ref) {
|
|
|
304
308
|
onDismiss: onClose,
|
|
305
309
|
onUnmount: onUnmount,
|
|
306
310
|
mountNode: mountNode,
|
|
311
|
+
shouldCloseOnDocumentClick: false,
|
|
307
312
|
renderHeader: () => renderHeader(title, settings, onKeyDown, handleAlertDismissal, onClose),
|
|
308
313
|
renderBody: () => renderBody(settings, dispatch, editor, editing, !replaceAll, nameRef, canvasOrigin, isLoading),
|
|
309
314
|
renderFooter: () => renderFooter(status, onClose, handleSubmit, editing, replaceAll, setReplaceAll, applyRef, isModified.current),
|
|
@@ -21,20 +21,20 @@ import { instUiIconsArray } from '../../../util/instui-icon-helper'; // @ts-igno
|
|
|
21
21
|
|
|
22
22
|
import { IconLtiSolid } from '@instructure/ui-icons/es/svg';
|
|
23
23
|
export function externalToolsForToolbar(tools) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const set = new Map(); // Remove possible overlaps between favorited and
|
|
24
|
+
// Limit of not on_by_default but favorited tools is 2
|
|
25
|
+
const favorited = tools.filter(it => it.favorite && !it.on_by_default).slice(0, 2) || [];
|
|
26
|
+
const onByDefault = tools.filter(it => it.on_by_default && it.favorite) || [];
|
|
27
|
+
const set = new Map(); // Remove possible overlaps between favorited and onByDefault, otherwise
|
|
28
28
|
// we'd have duplicate buttons in the toolbar.
|
|
29
29
|
|
|
30
|
-
for (const toolInfo of favorited.concat(
|
|
30
|
+
for (const toolInfo of favorited.concat(onByDefault)) {
|
|
31
31
|
set.set(toolInfo.id, toolInfo);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return Array.from(set.values()).sort((a, b) => {
|
|
35
|
-
if (a.
|
|
35
|
+
if (a.on_by_default && !b.on_by_default) {
|
|
36
36
|
return -1;
|
|
37
|
-
} else if (!a.
|
|
37
|
+
} else if (!a.on_by_default && b.on_by_default) {
|
|
38
38
|
return 1;
|
|
39
39
|
} else {
|
|
40
40
|
// This *should* always be a string, but there might be cases where it isn't,
|
|
@@ -107,8 +107,8 @@ export class RceToolWrapper {
|
|
|
107
107
|
return this.toolInfo.use_tray;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
get
|
|
111
|
-
return this.toolInfo.
|
|
110
|
+
get on_by_default() {
|
|
111
|
+
return this.toolInfo.on_by_default;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
asToolbarButton() {
|
|
@@ -131,6 +131,26 @@ export default class ExternalToolDialog extends React.Component {
|
|
|
131
131
|
this.handleInfoAlertBlur = () => this.setState({
|
|
132
132
|
infoAlert: null
|
|
133
133
|
});
|
|
134
|
+
|
|
135
|
+
this.calcIFrameHeight = () => {
|
|
136
|
+
var _this$state$button, _this$state$button2;
|
|
137
|
+
|
|
138
|
+
if ((_this$state$button = this.state.button) !== null && _this$state$button !== void 0 && _this$state$button.use_tray) {
|
|
139
|
+
return '100%';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const toolDefinedHeight = (_this$state$button2 = this.state.button) === null || _this$state$button2 === void 0 ? void 0 : _this$state$button2.height;
|
|
143
|
+
const iFrameHeight = toolDefinedHeight !== null && toolDefinedHeight !== void 0 ? toolDefinedHeight : Math.max(Math.min(window.innerHeight - 100, 550), 100);
|
|
144
|
+
const modalMaxHeight = '95';
|
|
145
|
+
const modalHeaderHeightWithPadding = '5.5rem';
|
|
146
|
+
const complexHeightWithDVH = `min(${iFrameHeight}px, calc(${modalMaxHeight}dvh - ${modalHeaderHeightWithPadding}))`;
|
|
147
|
+
|
|
148
|
+
if (CSS.supports('height', complexHeightWithDVH)) {
|
|
149
|
+
return complexHeightWithDVH;
|
|
150
|
+
} else {
|
|
151
|
+
return `${iFrameHeight}px`;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
open(button) {
|
|
@@ -202,12 +222,11 @@ export default class ExternalToolDialog extends React.Component {
|
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
render() {
|
|
205
|
-
var _state$button, _props$env$rceWrapper, _props$env$rceWrapper2, _state$button$title, _state$button2, _state$button3, _state$button$width, _state$button4
|
|
225
|
+
var _state$button, _props$env$rceWrapper, _props$env$rceWrapper2, _state$button$title, _state$button2, _state$button3, _state$button$width, _state$button4;
|
|
206
226
|
|
|
207
227
|
const state = this.state;
|
|
208
228
|
const props = this.props;
|
|
209
229
|
const label = formatMessage('Embed content from External Tool');
|
|
210
|
-
const frameHeight = Math.max(Math.min(window.innerHeight - 100, 550), 100);
|
|
211
230
|
const Overlay = (_state$button = state.button) !== null && _state$button !== void 0 && _state$button.use_tray ? ExternalToolDialogTray : ExternalToolDialogModal;
|
|
212
231
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("form", {
|
|
213
232
|
ref: this.formRef,
|
|
@@ -272,8 +291,8 @@ export default class ExternalToolDialog extends React.Component {
|
|
|
272
291
|
src: "",
|
|
273
292
|
id: "external_tool_button_frame",
|
|
274
293
|
style: {
|
|
294
|
+
height: this.calcIFrameHeight(),
|
|
275
295
|
width: (_state$button3 = state.button) !== null && _state$button3 !== void 0 && _state$button3.use_tray ? '100%' : (_state$button$width = (_state$button4 = state.button) === null || _state$button4 === void 0 ? void 0 : _state$button4.width) !== null && _state$button$width !== void 0 ? _state$button$width : 800,
|
|
276
|
-
height: (_state$button5 = state.button) !== null && _state$button5 !== void 0 && _state$button5.use_tray ? '100%' : (_state$button$height = (_state$button6 = state.button) === null || _state$button6 === void 0 ? void 0 : _state$button6.height) !== null && _state$button$height !== void 0 ? _state$button$height : frameHeight,
|
|
277
296
|
border: '0',
|
|
278
297
|
display: 'block',
|
|
279
298
|
visibility: state.iframeLoaded ? 'visible' : 'hidden'
|
|
@@ -288,6 +307,9 @@ export default class ExternalToolDialog extends React.Component {
|
|
|
288
307
|
,
|
|
289
308
|
onFocus: this.handleInfoAlertFocus,
|
|
290
309
|
onBlur: this.handleInfoAlertBlur,
|
|
310
|
+
style: this.afterInfoAlertRef.current != null && state.infoAlert === this.afterInfoAlertRef.current ? {} : {
|
|
311
|
+
bottom: '0'
|
|
312
|
+
},
|
|
291
313
|
className: this.afterInfoAlertRef.current != null && state.infoAlert === this.afterInfoAlertRef.current ? '' : 'screenreader-only'
|
|
292
314
|
}, /*#__PURE__*/React.createElement(Alert, {
|
|
293
315
|
margin: "small"
|
|
@@ -68,7 +68,7 @@ function registerFavoriteAppsToolbarButtons(editor) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function registerAppsToolbarButton(editor) {
|
|
71
|
-
const tooltip =
|
|
71
|
+
const tooltip = 'apps-temp';
|
|
72
72
|
editor.ui.registry.addMenuButton('lti_mru_button', {
|
|
73
73
|
tooltip,
|
|
74
74
|
icon: 'lti',
|
|
@@ -79,6 +79,9 @@ function registerAppsToolbarButton(editor) {
|
|
|
79
79
|
},
|
|
80
80
|
|
|
81
81
|
onSetup(_api) {
|
|
82
|
+
const e = document.querySelector("button[title='apps-temp']");
|
|
83
|
+
e === null || e === void 0 ? void 0 : e.setAttribute('title', formatMessage('Apps'));
|
|
84
|
+
e === null || e === void 0 ? void 0 : e.setAttribute('id', 'plug-apps-button');
|
|
82
85
|
return () => undefined;
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -15,23 +15,24 @@
|
|
|
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 React, {
|
|
18
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
19
19
|
import { bool, element, func, instanceOf, oneOfType, shape, string } from 'prop-types';
|
|
20
20
|
import { Tray } from '@instructure/ui-tray';
|
|
21
21
|
import { CloseButton, Button } from '@instructure/ui-buttons';
|
|
22
22
|
import { Heading } from '@instructure/ui-heading';
|
|
23
|
-
import { Spinner } from '@instructure/ui-spinner';
|
|
24
23
|
import { Flex } from '@instructure/ui-flex';
|
|
25
24
|
import { View } from '@instructure/ui-view';
|
|
26
25
|
import ErrorBoundary from './ErrorBoundary';
|
|
27
26
|
import Bridge from '../../../bridge/Bridge';
|
|
28
27
|
import formatMessage from '../../../format-message';
|
|
29
|
-
import Filter
|
|
28
|
+
import Filter from './Filter';
|
|
29
|
+
import { useFilterSettings } from './useFilterSettings';
|
|
30
30
|
import { getTrayHeight } from './trayUtils';
|
|
31
31
|
import { ICON_MAKER_ICONS } from '../instructure_icon_maker/svg/constants';
|
|
32
32
|
import { getLinkContentFromEditor } from './ContentSelection';
|
|
33
33
|
import { LinkDisplay } from './LinkDisplay';
|
|
34
34
|
import { showFlashAlert } from '../../../common/FlashAlert';
|
|
35
|
+
import { FILTER_SETTINGS_BY_PLUGIN, DynamicPanel, isLoading } from './canvasContentUtils';
|
|
35
36
|
/**
|
|
36
37
|
* Returns the translated tray label
|
|
37
38
|
* @param {string} contentType - The type of content showing on tray
|
|
@@ -71,160 +72,6 @@ function getTrayLabel(contentType, contentSubtype, contextType) {
|
|
|
71
72
|
// Shouldn't ever get here
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
-
const thePanels = {
|
|
76
|
-
icon_maker_icons: /*#__PURE__*/React.lazy(() => import('../instructure_icon_maker/components/SavedIconMakerList')),
|
|
77
|
-
links: /*#__PURE__*/React.lazy(() => import('../instructure_links/components/LinksPanel')),
|
|
78
|
-
images: /*#__PURE__*/React.lazy(() => import('../instructure_image/Images')),
|
|
79
|
-
documents: /*#__PURE__*/React.lazy(() => import('../instructure_documents/components/DocumentsPanel')),
|
|
80
|
-
media: /*#__PURE__*/React.lazy(() => import('../instructure_record/MediaPanel')),
|
|
81
|
-
all: /*#__PURE__*/React.lazy(() => import('./RceFileBrowser')),
|
|
82
|
-
unknown: /*#__PURE__*/React.lazy(() => import('./UnknownFileTypePanel'))
|
|
83
|
-
}; // Returns a Suspense wrapped lazy loaded component
|
|
84
|
-
// pulled from useLazy's cache
|
|
85
|
-
|
|
86
|
-
function DynamicPanel(props) {
|
|
87
|
-
let key = '';
|
|
88
|
-
|
|
89
|
-
if (props.contentType === 'links') {
|
|
90
|
-
key = 'links';
|
|
91
|
-
} else {
|
|
92
|
-
key = props.contentSubtype in thePanels ? props.contentSubtype : 'unknown';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const Component = thePanels[key];
|
|
96
|
-
return /*#__PURE__*/React.createElement(Suspense, {
|
|
97
|
-
fallback: /*#__PURE__*/React.createElement(Spinner, {
|
|
98
|
-
renderTitle: renderLoading,
|
|
99
|
-
size: "large"
|
|
100
|
-
})
|
|
101
|
-
}, /*#__PURE__*/React.createElement(Component, props));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function renderLoading() {
|
|
105
|
-
return formatMessage('Loading');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const FILTER_SETTINGS_BY_PLUGIN = {
|
|
109
|
-
user_documents: {
|
|
110
|
-
contextType: 'user',
|
|
111
|
-
contentType: 'user_files',
|
|
112
|
-
contentSubtype: 'documents',
|
|
113
|
-
sortValue: 'date_added',
|
|
114
|
-
sortDir: 'desc',
|
|
115
|
-
searchString: ''
|
|
116
|
-
},
|
|
117
|
-
course_documents: {
|
|
118
|
-
contextType: 'course',
|
|
119
|
-
contentType: 'course_files',
|
|
120
|
-
contentSubtype: 'documents',
|
|
121
|
-
sortValue: 'date_added',
|
|
122
|
-
sortDir: 'desc',
|
|
123
|
-
searchString: ''
|
|
124
|
-
},
|
|
125
|
-
group_documents: {
|
|
126
|
-
contextType: 'group',
|
|
127
|
-
contentType: 'group_files',
|
|
128
|
-
contentSubtype: 'documents',
|
|
129
|
-
sortValue: 'date_added',
|
|
130
|
-
sortDir: 'desc',
|
|
131
|
-
searchString: ''
|
|
132
|
-
},
|
|
133
|
-
user_images: {
|
|
134
|
-
contextType: 'user',
|
|
135
|
-
contentType: 'user_files',
|
|
136
|
-
contentSubtype: 'images',
|
|
137
|
-
sortValue: 'date_added',
|
|
138
|
-
sortDir: 'desc',
|
|
139
|
-
searchString: ''
|
|
140
|
-
},
|
|
141
|
-
course_images: {
|
|
142
|
-
contextType: 'course',
|
|
143
|
-
contentType: 'course_files',
|
|
144
|
-
contentSubtype: 'images',
|
|
145
|
-
sortValue: 'date_added',
|
|
146
|
-
sortDir: 'desc',
|
|
147
|
-
searchString: ''
|
|
148
|
-
},
|
|
149
|
-
group_images: {
|
|
150
|
-
contextType: 'group',
|
|
151
|
-
contentType: 'group_files',
|
|
152
|
-
contentSubtype: 'images',
|
|
153
|
-
sortValue: 'date_added',
|
|
154
|
-
sortDir: 'desc',
|
|
155
|
-
searchString: ''
|
|
156
|
-
},
|
|
157
|
-
user_media: {
|
|
158
|
-
contextType: 'user',
|
|
159
|
-
contentType: 'user_files',
|
|
160
|
-
contentSubtype: 'media',
|
|
161
|
-
sortValue: 'date_added',
|
|
162
|
-
sortDir: 'desc',
|
|
163
|
-
searchString: ''
|
|
164
|
-
},
|
|
165
|
-
course_media: {
|
|
166
|
-
contextType: 'course',
|
|
167
|
-
contentType: 'course_files',
|
|
168
|
-
contentSubtype: 'media',
|
|
169
|
-
sortValue: 'date_added',
|
|
170
|
-
sortDir: 'desc',
|
|
171
|
-
searchString: ''
|
|
172
|
-
},
|
|
173
|
-
group_media: {
|
|
174
|
-
contextType: 'group',
|
|
175
|
-
contentType: 'group_files',
|
|
176
|
-
contentSubtype: 'media',
|
|
177
|
-
sortValue: 'date_added',
|
|
178
|
-
sortDir: 'desc',
|
|
179
|
-
searchString: ''
|
|
180
|
-
},
|
|
181
|
-
course_links: {
|
|
182
|
-
contextType: 'course',
|
|
183
|
-
contentType: 'links',
|
|
184
|
-
contentSubtype: 'all',
|
|
185
|
-
sortValue: 'date_added',
|
|
186
|
-
sortDir: 'desc',
|
|
187
|
-
searchString: ''
|
|
188
|
-
},
|
|
189
|
-
course_link_edit: {
|
|
190
|
-
contextType: 'course',
|
|
191
|
-
contentType: 'links',
|
|
192
|
-
contentSubtype: 'edit',
|
|
193
|
-
sortValue: 'date_added',
|
|
194
|
-
sortDir: 'desc',
|
|
195
|
-
searchString: ''
|
|
196
|
-
},
|
|
197
|
-
group_links: {
|
|
198
|
-
contextType: 'group',
|
|
199
|
-
contentType: 'links',
|
|
200
|
-
contentSubtype: 'all',
|
|
201
|
-
sortValue: 'date_added',
|
|
202
|
-
sortDir: 'desc',
|
|
203
|
-
searchString: ''
|
|
204
|
-
},
|
|
205
|
-
list_icon_maker_icons: {
|
|
206
|
-
contextType: 'course',
|
|
207
|
-
contentType: 'course_files',
|
|
208
|
-
contentSubtype: ICON_MAKER_ICONS,
|
|
209
|
-
sortValue: 'date_added',
|
|
210
|
-
sortDir: 'desc',
|
|
211
|
-
searchString: ''
|
|
212
|
-
},
|
|
213
|
-
all: {
|
|
214
|
-
contextType: 'course',
|
|
215
|
-
contentType: 'course_files',
|
|
216
|
-
contentSubtype: 'all',
|
|
217
|
-
sortValue: 'alphabetical',
|
|
218
|
-
sortDir: 'asc',
|
|
219
|
-
searchString: ''
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
function isLoading(sprops) {
|
|
224
|
-
var _sprops$collections$a, _sprops$collections$a2, _sprops$collections$d, _sprops$collections$m, _sprops$collections$q, _sprops$collections$w, _sprops$documents$cou, _sprops$documents$use, _sprops$documents$gro, _sprops$media$course, _sprops$media$user, _sprops$media$group, _sprops$all_files;
|
|
225
|
-
|
|
226
|
-
return ((_sprops$collections$a = sprops.collections.announcements) === null || _sprops$collections$a === void 0 ? void 0 : _sprops$collections$a.isLoading) || ((_sprops$collections$a2 = sprops.collections.assignments) === null || _sprops$collections$a2 === void 0 ? void 0 : _sprops$collections$a2.isLoading) || ((_sprops$collections$d = sprops.collections.discussions) === null || _sprops$collections$d === void 0 ? void 0 : _sprops$collections$d.isLoading) || ((_sprops$collections$m = sprops.collections.modules) === null || _sprops$collections$m === void 0 ? void 0 : _sprops$collections$m.isLoading) || ((_sprops$collections$q = sprops.collections.quizzes) === null || _sprops$collections$q === void 0 ? void 0 : _sprops$collections$q.isLoading) || ((_sprops$collections$w = sprops.collections.wikiPages) === null || _sprops$collections$w === void 0 ? void 0 : _sprops$collections$w.isLoading) || ((_sprops$documents$cou = sprops.documents.course) === null || _sprops$documents$cou === void 0 ? void 0 : _sprops$documents$cou.isLoading) || ((_sprops$documents$use = sprops.documents.user) === null || _sprops$documents$use === void 0 ? void 0 : _sprops$documents$use.isLoading) || ((_sprops$documents$gro = sprops.documents.group) === null || _sprops$documents$gro === void 0 ? void 0 : _sprops$documents$gro.isLoading) || ((_sprops$media$course = sprops.media.course) === null || _sprops$media$course === void 0 ? void 0 : _sprops$media$course.isLoading) || ((_sprops$media$user = sprops.media.user) === null || _sprops$media$user === void 0 ? void 0 : _sprops$media$user.isLoading) || ((_sprops$media$group = sprops.media.group) === null || _sprops$media$group === void 0 ? void 0 : _sprops$media$group.isLoading) || ((_sprops$all_files = sprops.all_files) === null || _sprops$all_files === void 0 ? void 0 : _sprops$all_files.isLoading);
|
|
227
|
-
}
|
|
228
75
|
/**
|
|
229
76
|
* This component is used within various plugins to handle loading in content
|
|
230
77
|
* from Canvas. It is essentially the main component.
|
|
@@ -533,7 +380,8 @@ function requiredWithoutSource(props, propName, componentName) {
|
|
|
533
380
|
if (props.source == null && props[propName] == null) {
|
|
534
381
|
throw new Error(`The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is \`${props[propName]}\`.`);
|
|
535
382
|
}
|
|
536
|
-
}
|
|
383
|
+
} // Changes made here may need to be reflected in the trayProps type in CanvasContentPanel
|
|
384
|
+
|
|
537
385
|
|
|
538
386
|
const trayPropsMap = {
|
|
539
387
|
canUploadFiles: bool.isRequired,
|
|
@@ -26,23 +26,6 @@ import { IconButton } from '@instructure/ui-buttons';
|
|
|
26
26
|
import { ScreenReaderContent } from '@instructure/ui-a11y-content';
|
|
27
27
|
import { ICON_MAKER_ICONS } from '../instructure_icon_maker/svg/constants';
|
|
28
28
|
import { IconLinkLine, IconFolderLine, IconImageLine, IconDocumentLine, IconAttachMediaLine, IconSearchLine, IconXLine } from '@instructure/ui-icons';
|
|
29
|
-
const DEFAULT_FILTER_SETTINGS = {
|
|
30
|
-
contentSubtype: 'all',
|
|
31
|
-
contentType: 'links',
|
|
32
|
-
sortValue: 'date_added',
|
|
33
|
-
searchString: ''
|
|
34
|
-
};
|
|
35
|
-
export function useFilterSettings(default_settings) {
|
|
36
|
-
const [filterSettings, setFilterSettings] = useState(default_settings || DEFAULT_FILTER_SETTINGS);
|
|
37
|
-
|
|
38
|
-
function updateFilterSettings(nextSettings) {
|
|
39
|
-
setFilterSettings({ ...filterSettings,
|
|
40
|
-
...nextSettings
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return [filterSettings, updateFilterSettings];
|
|
45
|
-
}
|
|
46
29
|
|
|
47
30
|
function fileLabelFromContext(contextType) {
|
|
48
31
|
switch (contextType) {
|
|
@@ -59,7 +59,8 @@ export const FixedContentTray = _ref => {
|
|
|
59
59
|
renderBody,
|
|
60
60
|
renderFooter,
|
|
61
61
|
bodyAs,
|
|
62
|
-
shouldJoinBodyAndFooter
|
|
62
|
+
shouldJoinBodyAndFooter,
|
|
63
|
+
shouldCloseOnDocumentClick
|
|
63
64
|
} = _ref;
|
|
64
65
|
return /*#__PURE__*/React.createElement(Tray, {
|
|
65
66
|
"data-mce-component": true,
|
|
@@ -69,7 +70,7 @@ export const FixedContentTray = _ref => {
|
|
|
69
70
|
onExited: onUnmount,
|
|
70
71
|
open: isOpen,
|
|
71
72
|
placement: "end",
|
|
72
|
-
shouldCloseOnDocumentClick:
|
|
73
|
+
shouldCloseOnDocumentClick: shouldCloseOnDocumentClick,
|
|
73
74
|
shouldContainFocus: true,
|
|
74
75
|
shouldReturnFocus: true,
|
|
75
76
|
size: "regular"
|
|
@@ -103,7 +104,8 @@ FixedContentTray.propTypes = {
|
|
|
103
104
|
onUnmount: PropTypes.func,
|
|
104
105
|
mountNode: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
|
|
105
106
|
bodyAs: PropTypes.string,
|
|
106
|
-
shouldJoinBodyAndFooter: PropTypes.bool
|
|
107
|
+
shouldJoinBodyAndFooter: PropTypes.bool,
|
|
108
|
+
shouldCloseOnDocumentClick: PropTypes.bool
|
|
107
109
|
};
|
|
108
110
|
FixedContentTray.defaultProps = {
|
|
109
111
|
title: null,
|
|
@@ -111,5 +113,6 @@ FixedContentTray.defaultProps = {
|
|
|
111
113
|
onDismiss: () => {},
|
|
112
114
|
onUnmount: () => {},
|
|
113
115
|
bodyAs: 'div',
|
|
114
|
-
shouldJoinBodyAndFooter: false
|
|
116
|
+
shouldJoinBodyAndFooter: false,
|
|
117
|
+
shouldCloseOnDocumentClick: true
|
|
115
118
|
};
|
|
@@ -44,7 +44,8 @@ const ImageOptionsForm = _ref => {
|
|
|
44
44
|
messagesForSize,
|
|
45
45
|
hideDimensions,
|
|
46
46
|
id = 'image-options-form',
|
|
47
|
-
isIconMaker = false
|
|
47
|
+
isIconMaker = false,
|
|
48
|
+
forBlockEditorUse = false
|
|
48
49
|
} = _ref;
|
|
49
50
|
const TYPE = isIconMaker ? formatMessage('icon') : formatMessage('image');
|
|
50
51
|
const tooltipText = formatMessage('Used by screen readers to describe the content of an {TYPE}', {
|
|
@@ -95,7 +96,7 @@ const ImageOptionsForm = _ref => {
|
|
|
95
96
|
TYPE_UPPER
|
|
96
97
|
}),
|
|
97
98
|
onChange: handleIsDecorativeChange
|
|
98
|
-
})), !isIconMaker && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
99
|
+
})), !isIconMaker && /*#__PURE__*/React.createElement(React.Fragment, null, !forBlockEditorUse && /*#__PURE__*/React.createElement(Flex.Item, {
|
|
99
100
|
padding: "small"
|
|
100
101
|
}, /*#__PURE__*/React.createElement(RadioInputGroup, {
|
|
101
102
|
description: formatMessage('Display Options'),
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import _pt from "prop-types";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (C) 2024 - present Instructure, Inc.
|
|
5
|
+
*
|
|
6
|
+
* This file is part of Canvas.
|
|
7
|
+
*
|
|
8
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
|
9
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
|
10
|
+
* Software Foundation, version 3 of the License.
|
|
11
|
+
*
|
|
12
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
13
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
14
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
15
|
+
* details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU Affero General Public License along
|
|
18
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
*/
|
|
20
|
+
import React, { useState } from 'react';
|
|
21
|
+
import { Flex } from '@instructure/ui-flex';
|
|
22
|
+
import ErrorBoundary from '../ErrorBoundary';
|
|
23
|
+
import { useFilterSettings } from '../useFilterSettings';
|
|
24
|
+
import PanelFilter from './PanelFilter';
|
|
25
|
+
import { FILTER_SETTINGS_BY_PLUGIN, DynamicPanel } from '../canvasContentUtils';
|
|
26
|
+
import { useStoreProps } from '../StoreContext';
|
|
27
|
+
// TODO: Component is only validated for images, need to validate for other content types
|
|
28
|
+
export default function CanvasContentPanel(_ref) {
|
|
29
|
+
let {
|
|
30
|
+
trayProps,
|
|
31
|
+
canvasOrigin,
|
|
32
|
+
plugin,
|
|
33
|
+
setFileUrl
|
|
34
|
+
} = _ref;
|
|
35
|
+
const [filterSettings, setFilterSettings] = useFilterSettings(FILTER_SETTINGS_BY_PLUGIN[plugin]);
|
|
36
|
+
const [link, setLink] = useState(null);
|
|
37
|
+
const [hasLoaded, setHasLoaded] = useState(false); // storeProps has functions that collide with what we want to do in a block editor setting
|
|
38
|
+
|
|
39
|
+
const baseStoreProps = useStoreProps();
|
|
40
|
+
const {
|
|
41
|
+
onImageEmbed: _,
|
|
42
|
+
...storeProps
|
|
43
|
+
} = baseStoreProps;
|
|
44
|
+
|
|
45
|
+
function handleFilterChange(newFilter, onChangeContext, onChangeSearchString, onChangeSortBy) {
|
|
46
|
+
const newFilterSettings = { ...newFilter
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (newFilterSettings.sortValue) {
|
|
50
|
+
newFilterSettings.sortDir = newFilterSettings.sortValue === 'alphabetical' ? 'asc' : 'desc';
|
|
51
|
+
onChangeSortBy({
|
|
52
|
+
sort: newFilterSettings.sortValue,
|
|
53
|
+
dir: newFilterSettings.sortDir
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if ('searchString' in newFilterSettings && filterSettings.searchString !== newFilterSettings.searchString) {
|
|
58
|
+
onChangeSearchString(newFilterSettings.searchString);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setFilterSettings(newFilterSettings);
|
|
62
|
+
|
|
63
|
+
if (newFilterSettings.contentType) {
|
|
64
|
+
let contextType, contextId;
|
|
65
|
+
|
|
66
|
+
switch (newFilterSettings.contentType) {
|
|
67
|
+
case 'user_files':
|
|
68
|
+
contextType = 'user';
|
|
69
|
+
contextId = trayProps.containingContext.userId;
|
|
70
|
+
break;
|
|
71
|
+
|
|
72
|
+
case 'group_files':
|
|
73
|
+
contextType = 'group';
|
|
74
|
+
contextId = trayProps.containingContext.contextId;
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'course_files':
|
|
78
|
+
contextType = trayProps.contextType;
|
|
79
|
+
contextId = trayProps.containingContext.contextId;
|
|
80
|
+
break;
|
|
81
|
+
|
|
82
|
+
case 'links':
|
|
83
|
+
contextType = trayProps.containingContext.contextType;
|
|
84
|
+
contextId = trayProps.containingContext.contextId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
onChangeContext({
|
|
88
|
+
contextType,
|
|
89
|
+
contextId
|
|
90
|
+
}); // context is only changed on load
|
|
91
|
+
|
|
92
|
+
setHasLoaded(true);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const handleImageClick = image => {
|
|
97
|
+
setFileUrl(image.href);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return /*#__PURE__*/React.createElement(Flex, {
|
|
101
|
+
as: "div",
|
|
102
|
+
direction: "column",
|
|
103
|
+
tabIndex: -1
|
|
104
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
105
|
+
padding: "medium"
|
|
106
|
+
}, /*#__PURE__*/React.createElement(PanelFilter, Object.assign({}, filterSettings, {
|
|
107
|
+
onChange: newFilter => {
|
|
108
|
+
handleFilterChange(newFilter, storeProps.onChangeContext, storeProps.onChangeSearchString, storeProps.onChangeSortBy);
|
|
109
|
+
}
|
|
110
|
+
}))), /*#__PURE__*/React.createElement(Flex.Item, {
|
|
111
|
+
shouldGrow: true,
|
|
112
|
+
shouldShrink: true,
|
|
113
|
+
margin: "xx-small xxx-small 0"
|
|
114
|
+
}, hasLoaded && /*#__PURE__*/React.createElement(Flex, {
|
|
115
|
+
justifyItems: "space-between",
|
|
116
|
+
direction: "column",
|
|
117
|
+
height: "100%"
|
|
118
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
119
|
+
shouldGrow: true,
|
|
120
|
+
shouldShrink: true
|
|
121
|
+
}, /*#__PURE__*/React.createElement(ErrorBoundary, null, /*#__PURE__*/React.createElement(DynamicPanel, Object.assign({
|
|
122
|
+
contentType: filterSettings.contentType,
|
|
123
|
+
contentSubtype: filterSettings.contentSubtype,
|
|
124
|
+
sortBy: {
|
|
125
|
+
sort: filterSettings.sortValue,
|
|
126
|
+
order: filterSettings.sortDir
|
|
127
|
+
},
|
|
128
|
+
searchString: filterSettings.searchString,
|
|
129
|
+
canvasOrigin: canvasOrigin,
|
|
130
|
+
context: {
|
|
131
|
+
type: trayProps.contextType,
|
|
132
|
+
id: trayProps.contextId
|
|
133
|
+
},
|
|
134
|
+
editing: false,
|
|
135
|
+
onEditClick: setLink,
|
|
136
|
+
selectedLink: link,
|
|
137
|
+
onImageEmbed: handleImageClick
|
|
138
|
+
}, storeProps)))))));
|
|
139
|
+
}
|
|
140
|
+
CanvasContentPanel.propTypes = {
|
|
141
|
+
trayProps: _pt.shape({
|
|
142
|
+
canUploadFiles: _pt.bool.isRequired,
|
|
143
|
+
contextId: _pt.string.isRequired,
|
|
144
|
+
contextType: _pt.string.isRequired,
|
|
145
|
+
containingContext: _pt.shape({
|
|
146
|
+
contextType: _pt.string.isRequired,
|
|
147
|
+
contextId: _pt.string.isRequired,
|
|
148
|
+
userId: _pt.string.isRequired
|
|
149
|
+
}).isRequired,
|
|
150
|
+
filesTabDisabled: _pt.bool.isRequired,
|
|
151
|
+
host: _pt.string.isRequired,
|
|
152
|
+
jwt: _pt.string.isRequired,
|
|
153
|
+
source: _pt.shape({}).isRequired,
|
|
154
|
+
themeUrl: _pt.string.isRequired,
|
|
155
|
+
storeProps: _pt.any.isRequired
|
|
156
|
+
}).isRequired,
|
|
157
|
+
canvasOrigin: _pt.string.isRequired,
|
|
158
|
+
plugin: _pt.any.isRequired,
|
|
159
|
+
setFileUrl: _pt.func.isRequired
|
|
160
|
+
};
|
|
@@ -273,6 +273,7 @@ export default function ComputerPanel(_ref) {
|
|
|
273
273
|
return /*#__PURE__*/React.createElement("div", {
|
|
274
274
|
ref: panelRef
|
|
275
275
|
}, /*#__PURE__*/React.createElement(FileDrop, {
|
|
276
|
+
"data-testid": "filedrop",
|
|
276
277
|
accept: accept,
|
|
277
278
|
onDropAccepted: _ref2 => {
|
|
278
279
|
let [file] = _ref2;
|