@instructure/canvas-rce 5.10.0 → 5.11.1
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 +42 -0
- package/Dockerfile +1 -1
- package/es/common/mimeClass.js +70 -67
- package/es/enhance-user-content/doc_previews.js +1 -1
- package/es/enhance-user-content/enhance_user_content.js +9 -1
- package/es/getThemeVars.js +3 -4
- package/es/rce/RCE.js +1 -3
- package/es/rce/RCEWrapper.js +3 -67
- package/es/rce/RceHtmlEditor.js +28 -8
- package/es/rce/plugins/instructure_links/components/Link.js +3 -9
- package/es/rce/plugins/instructure_links/components/LinkSet.js +4 -8
- package/es/rce/plugins/instructure_links/components/NoResults.js +5 -10
- package/es/rce/plugins/instructure_links/plugin.js +1 -7
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +1 -2
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogTray.js +6 -12
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog.js +2 -2
- package/es/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/ResourceLinkContentItem.js +1 -1
- package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +7 -2
- package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +3 -9
- package/es/rce/plugins/instructure_wordcount/components/WordCountModal.js +8 -16
- package/es/rce/plugins/shared/CanvasContentTray.js +7 -1
- package/es/rce/plugins/shared/fileTypeUtils.js +14 -6
- package/es/rce/plugins/tinymce-a11y-checker/components/{color-field.js → ColorField.js} +9 -7
- package/es/rce/plugins/tinymce-a11y-checker/components/checker.js +27 -24
- package/es/rce/root.js +1 -3
- package/es/rce/transformContent.js +8 -0
- package/es/sidebar/actions/upload.js +3 -1
- package/jest/jest-setup.js +2 -0
- package/lib/common/mimeClass.js +70 -67
- package/lib/enhance-user-content/doc_previews.js +1 -1
- package/lib/enhance-user-content/enhance_user_content.js +9 -1
- package/lib/getThemeVars.js +3 -4
- package/lib/rce/RCE.js +1 -3
- package/lib/rce/RCEWrapper.js +3 -67
- package/lib/rce/RceHtmlEditor.js +28 -8
- package/lib/rce/plugins/instructure_links/components/Link.js +3 -9
- package/lib/rce/plugins/instructure_links/components/LinkSet.js +4 -8
- package/lib/rce/plugins/instructure_links/components/NoResults.js +5 -10
- package/lib/rce/plugins/instructure_links/plugin.js +1 -7
- package/lib/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialog.js +1 -2
- package/lib/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogTray.js +6 -12
- package/lib/rce/plugins/instructure_rce_external_tools/components/ExternalToolSelectionDialog/ExternalToolSelectionDialog.js +2 -2
- package/lib/rce/plugins/instructure_rce_external_tools/lti13-content-items/models/ResourceLinkContentItem.js +1 -1
- package/lib/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +7 -2
- package/lib/rce/plugins/instructure_record/VideoOptionsTray/index.js +3 -9
- package/lib/rce/plugins/instructure_wordcount/components/WordCountModal.js +8 -16
- package/lib/rce/plugins/shared/CanvasContentTray.js +7 -1
- package/lib/rce/plugins/shared/fileTypeUtils.js +14 -6
- package/lib/rce/plugins/tinymce-a11y-checker/components/{color-field.js → ColorField.js} +9 -7
- package/lib/rce/plugins/tinymce-a11y-checker/components/checker.js +27 -24
- package/lib/rce/root.js +1 -3
- package/lib/rce/transformContent.js +8 -0
- package/lib/sidebar/actions/upload.js +3 -1
- package/locales/en.json +1438 -89
- package/package.json +52 -51
|
@@ -216,8 +216,16 @@ export function enhanceUserContent() {
|
|
|
216
216
|
iframeElem.setAttribute('src', addParentFrameContextToUrl(src, containingCanvasLtiToolId));
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
|
-
}
|
|
219
|
+
} // tell LTI tools that they are launching from within the active RCE
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
unenhanced_elem.querySelectorAll('iframe[src]').forEach(iframeElem => {
|
|
223
|
+
const src = iframeElem.getAttribute('src');
|
|
220
224
|
|
|
225
|
+
if (src.startsWith(canvasOrigin)) {
|
|
226
|
+
iframeElem.setAttribute('src', src.replace('display=in_rce', 'display=borderless'));
|
|
227
|
+
}
|
|
228
|
+
});
|
|
221
229
|
unenhanced_elem.querySelectorAll('a:not(.not_external, .external)').forEach(childLink => {
|
|
222
230
|
if (!isExternalLink(childLink, canvasOrigin)) return;
|
|
223
231
|
if (childLink.tagName === 'IMG' || childLink.querySelectorAll('img').length > 0) return;
|
package/lib/getThemeVars.js
CHANGED
|
@@ -15,8 +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
|
-
import {
|
|
19
|
-
|
|
18
|
+
import { getRegistry } from '@instructure/theme-registry';
|
|
20
19
|
import { merge, cloneDeep } from 'lodash'; // The running theme is the running theme for this page load, and it never
|
|
21
20
|
// changes, so there's no point in doing the work more than once.
|
|
22
21
|
|
|
@@ -28,13 +27,13 @@ function getThemeVars() {
|
|
|
28
27
|
defaultThemeKey,
|
|
29
28
|
overrides,
|
|
30
29
|
themes
|
|
31
|
-
} =
|
|
30
|
+
} = getRegistry(); // Just assume the "canvas" theme if the default key is null. This will
|
|
32
31
|
// never happen in the live app because one way or another a theme gets
|
|
33
32
|
// used, but unit tests don't always do that.
|
|
34
33
|
// Also we have to cloneDeep this because the merge below is about to
|
|
35
34
|
// mutate the whole thing.
|
|
36
35
|
|
|
37
|
-
const variables = cloneDeep(themes[defaultThemeKey !== null && defaultThemeKey !== void 0 ? defaultThemeKey : 'canvas']
|
|
36
|
+
const variables = cloneDeep(themes[defaultThemeKey !== null && defaultThemeKey !== void 0 ? defaultThemeKey : 'canvas']);
|
|
38
37
|
merge(variables, overrides);
|
|
39
38
|
memoizedVariables = {
|
|
40
39
|
variables,
|
package/lib/rce/RCE.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
var _process, _process$env;
|
|
2
|
-
|
|
3
1
|
// @ts-nocheck
|
|
4
2
|
|
|
5
3
|
/*
|
|
@@ -29,7 +27,7 @@ import tinyRCE from './tinyRCE';
|
|
|
29
27
|
import getTranslations from '../getTranslations';
|
|
30
28
|
import '@instructure/canvas-theme';
|
|
31
29
|
|
|
32
|
-
if (!
|
|
30
|
+
if (!process || !process.env || !undefined) {
|
|
33
31
|
formatMessage.setup({
|
|
34
32
|
locale: 'en',
|
|
35
33
|
generateId: require('format-message-generate-id/underscored_crc32'),
|
package/lib/rce/RCEWrapper.js
CHANGED
|
@@ -2714,67 +2714,9 @@ class RCEWrapper extends React.Component {
|
|
|
2714
2714
|
|
|
2715
2715
|
this.checkAccessibility();
|
|
2716
2716
|
this.fixToolbarKeyboardNavigation();
|
|
2717
|
-
this.forwardPostMessages();
|
|
2718
2717
|
(_this$props$onInitted = (_this$props = this.props).onInitted) === null || _this$props$onInitted === void 0 ? void 0 : _this$props$onInitted.call(_this$props, editor);
|
|
2719
2718
|
};
|
|
2720
2719
|
|
|
2721
|
-
this.forwardPostMessages = () => {
|
|
2722
|
-
const windowReferences = [];
|
|
2723
|
-
const rceWindow = this.editor.getWin(); // explicitly assign name for reference by parent window
|
|
2724
|
-
|
|
2725
|
-
rceWindow.name = `${RCEWrapper.editorFrameName}_${this.id}`;
|
|
2726
|
-
rceWindow.addEventListener('message', this.forwardPostMessagesHandler(rceWindow, windowReferences));
|
|
2727
|
-
};
|
|
2728
|
-
|
|
2729
|
-
this.forwardPostMessagesHandler = (rceWindow, windowReferences) => e => {
|
|
2730
|
-
let message;
|
|
2731
|
-
|
|
2732
|
-
try {
|
|
2733
|
-
message = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
|
|
2734
|
-
} catch (err) {
|
|
2735
|
-
// unparseable message may not be meant for our handlers
|
|
2736
|
-
return false;
|
|
2737
|
-
} // NOTE: the code to encode/decode `sourceToolInfo` is duplicated in
|
|
2738
|
-
// the ui/features/post_message_forwarding/index.ts, and
|
|
2739
|
-
// cannot be DRY'd because RCE is in a package
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
if (e.origin === rceWindow.origin) {
|
|
2743
|
-
const {
|
|
2744
|
-
sourceToolInfo,
|
|
2745
|
-
...messageWithoutSourceToolInfo
|
|
2746
|
-
} = message;
|
|
2747
|
-
const targetOrigin = sourceToolInfo === null || sourceToolInfo === void 0 ? void 0 : sourceToolInfo.origin;
|
|
2748
|
-
const targetWindow = windowReferences[sourceToolInfo === null || sourceToolInfo === void 0 ? void 0 : sourceToolInfo.windowId];
|
|
2749
|
-
|
|
2750
|
-
if (!targetOrigin || !targetWindow) {
|
|
2751
|
-
return false;
|
|
2752
|
-
}
|
|
2753
|
-
|
|
2754
|
-
targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.postMessage(messageWithoutSourceToolInfo, targetOrigin);
|
|
2755
|
-
} else {
|
|
2756
|
-
// message is from tool, forward to Canvas window
|
|
2757
|
-
// We can't forward the whole `e.source` window in the postMessage,
|
|
2758
|
-
// so we keep a list (`windowReferences`) of all windows we've received
|
|
2759
|
-
// messages from, and include the index into that list as `windowId`
|
|
2760
|
-
let windowId = windowReferences.indexOf(e.source);
|
|
2761
|
-
|
|
2762
|
-
if (windowId === -1) {
|
|
2763
|
-
windowReferences.push(e.source);
|
|
2764
|
-
windowId = windowReferences.length - 1;
|
|
2765
|
-
}
|
|
2766
|
-
|
|
2767
|
-
const newMessage = { ...message,
|
|
2768
|
-
sourceToolInfo: {
|
|
2769
|
-
origin: e.origin,
|
|
2770
|
-
windowId
|
|
2771
|
-
},
|
|
2772
|
-
frameName: rceWindow.name
|
|
2773
|
-
};
|
|
2774
|
-
rceWindow.parent.postMessage(newMessage, rceWindow.origin);
|
|
2775
|
-
}
|
|
2776
|
-
};
|
|
2777
|
-
|
|
2778
2720
|
this.fixToolbarKeyboardNavigation = () => {
|
|
2779
2721
|
var _this$_elementRef$cur2;
|
|
2780
2722
|
|
|
@@ -3200,19 +3142,15 @@ class RCEWrapper extends React.Component {
|
|
|
3200
3142
|
getRequiredFeatureStatuses() {
|
|
3201
3143
|
const {
|
|
3202
3144
|
new_math_equation_handling = false,
|
|
3203
|
-
rce_ux_improvements = false,
|
|
3204
3145
|
explicit_latex_typesetting = false,
|
|
3205
3146
|
rce_transform_loaded_content = false,
|
|
3206
|
-
media_links_use_attachment_id = false
|
|
3207
|
-
improved_no_results_messaging = false
|
|
3147
|
+
media_links_use_attachment_id = false
|
|
3208
3148
|
} = this.props.features;
|
|
3209
3149
|
return {
|
|
3210
3150
|
new_math_equation_handling,
|
|
3211
|
-
rce_ux_improvements,
|
|
3212
3151
|
explicit_latex_typesetting,
|
|
3213
3152
|
rce_transform_loaded_content,
|
|
3214
|
-
media_links_use_attachment_id
|
|
3215
|
-
improved_no_results_messaging
|
|
3153
|
+
media_links_use_attachment_id
|
|
3216
3154
|
};
|
|
3217
3155
|
}
|
|
3218
3156
|
|
|
@@ -3220,8 +3158,7 @@ class RCEWrapper extends React.Component {
|
|
|
3220
3158
|
return {
|
|
3221
3159
|
locale: normalizeLocale(this.props.language),
|
|
3222
3160
|
flashAlertTimeout: this.props.flashAlertTimeout,
|
|
3223
|
-
timezone: this.props.timezone
|
|
3224
|
-
lockedAttachments: this.props.lockedAttachments
|
|
3161
|
+
timezone: this.props.timezone
|
|
3225
3162
|
};
|
|
3226
3163
|
}
|
|
3227
3164
|
|
|
@@ -4257,7 +4194,6 @@ RCEWrapper.defaultProps = {
|
|
|
4257
4194
|
canvasOrigin: ''
|
|
4258
4195
|
};
|
|
4259
4196
|
RCEWrapper.skinCssInjected = false;
|
|
4260
|
-
RCEWrapper.editorFrameName = 'active_rce_frame';
|
|
4261
4197
|
|
|
4262
4198
|
function mergeMenuItems(standard, custom) {
|
|
4263
4199
|
var _custom$trim;
|
package/lib/rce/RceHtmlEditor.js
CHANGED
|
@@ -28,6 +28,28 @@ const RceHtmlEditor = /*#__PURE__*/React.forwardRef((_ref, editorRef) => {
|
|
|
28
28
|
const [code, setCode] = useState(props.code);
|
|
29
29
|
const label = formatMessage('html code editor');
|
|
30
30
|
const [dir, setDir] = useState(getComputedStyle(document.body, null).direction);
|
|
31
|
+
const [codeMirrorEditorDiv, setCodeMirrorEditorDiv] = useState(null);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
;
|
|
34
|
+
|
|
35
|
+
(async () => {
|
|
36
|
+
const p = new Promise(resolve => {
|
|
37
|
+
const timerid = setInterval(() => {
|
|
38
|
+
// scoping querySelector to the container div makes sure we're targeting this CodeEditor
|
|
39
|
+
// The CodeMirror docs (https://codemirror.net/doc/manual.html#styling)
|
|
40
|
+
// say this is the element we use to set the editor's height
|
|
41
|
+
const editor = editorRef.current.querySelector('.CodeMirror');
|
|
42
|
+
|
|
43
|
+
if (editor) {
|
|
44
|
+
clearInterval(timerid);
|
|
45
|
+
setCodeMirrorEditorDiv(editor);
|
|
46
|
+
resolve();
|
|
47
|
+
}
|
|
48
|
+
}, 60);
|
|
49
|
+
});
|
|
50
|
+
await p;
|
|
51
|
+
})();
|
|
52
|
+
}, [editorRef]);
|
|
31
53
|
useEffect(() => {
|
|
32
54
|
setCode(beautify.html(props.code)); // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
55
|
}, []);
|
|
@@ -57,14 +79,12 @@ const RceHtmlEditor = /*#__PURE__*/React.forwardRef((_ref, editorRef) => {
|
|
|
57
79
|
setDir(getComputedStyle(editorRef.current || document.body, null).direction);
|
|
58
80
|
}, [dir, editorRef]);
|
|
59
81
|
useEffect(() => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
editor.style.border = '0';
|
|
67
|
-
}, [props.height, editorRef]);
|
|
82
|
+
if (codeMirrorEditorDiv) {
|
|
83
|
+
codeMirrorEditorDiv.CodeMirror.setSize(null, props.height);
|
|
84
|
+
codeMirrorEditorDiv.style.margin = '0';
|
|
85
|
+
codeMirrorEditorDiv.style.border = '0';
|
|
86
|
+
}
|
|
87
|
+
}, [codeMirrorEditorDiv, props.height]);
|
|
68
88
|
const isFocused = useRef(false); // move cursor to the top of the html code when the editor is focused for the first time
|
|
69
89
|
|
|
70
90
|
const handleFocus = useCallback((editor, event) => {
|
|
@@ -31,8 +31,6 @@ import { IconDragHandleLine, IconPublishSolid, IconUnpublishedSolid } from '@ins
|
|
|
31
31
|
import RCEGlobals from '../../../RCEGlobals';
|
|
32
32
|
import { getIcon } from '../../shared/linkUtils';
|
|
33
33
|
export default function Link(props) {
|
|
34
|
-
var _RCEGlobals$getFeatur;
|
|
35
|
-
|
|
36
34
|
const internalLink = { ...props.link
|
|
37
35
|
};
|
|
38
36
|
const [isHovering, setIsHovering] = useState(false);
|
|
@@ -43,14 +41,10 @@ export default function Link(props) {
|
|
|
43
41
|
date_type
|
|
44
42
|
} = props.link;
|
|
45
43
|
const type = props.type === 'quizzes' && props.link.quiz_type === 'quizzes.next' ? 'quizzes.next' : props.type;
|
|
44
|
+
internalLink['data-course-type'] = type; // Only included published attr if it makes sense for the link type
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const publishable = !['navigation', 'announcements'].includes(type);
|
|
51
|
-
internalLink['data-published'] = publishable ? published : null;
|
|
52
|
-
}
|
|
53
|
-
|
|
46
|
+
const publishable = !['navigation', 'announcements'].includes(type);
|
|
47
|
+
internalLink['data-published'] = publishable ? published : null;
|
|
54
48
|
const Icon = getIcon(type);
|
|
55
49
|
const color = published ? 'success' : 'primary';
|
|
56
50
|
let dateString = null;
|
|
@@ -113,7 +113,7 @@ class LinkSet extends Component {
|
|
|
113
113
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ScreenReaderContent, {
|
|
114
114
|
id: this.describedByID
|
|
115
115
|
}, formatMessage('Click to insert a link into the editor.')), /*#__PURE__*/React.createElement(List, {
|
|
116
|
-
|
|
116
|
+
isUnstyled: true,
|
|
117
117
|
as: "ul",
|
|
118
118
|
margin: "0"
|
|
119
119
|
}, this.props.collection.links.map((link, index, array) => {
|
|
@@ -137,18 +137,14 @@ class LinkSet extends Component {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
renderEmptyIndicator() {
|
|
140
|
-
var
|
|
140
|
+
var _this$props$searchStr;
|
|
141
141
|
|
|
142
|
-
return
|
|
142
|
+
return /*#__PURE__*/React.createElement(NoResults, {
|
|
143
143
|
contextType: this.props.contextType,
|
|
144
144
|
contextId: this.props.contextId,
|
|
145
145
|
collectionType: this.props.type,
|
|
146
146
|
isSearchResult: ((_this$props$searchStr = this.props.searchString) === null || _this$props$searchStr === void 0 ? void 0 : _this$props$searchStr.length) >= 3
|
|
147
|
-
})
|
|
148
|
-
as: "div",
|
|
149
|
-
role: "alert",
|
|
150
|
-
padding: "medium"
|
|
151
|
-
}, formatMessage('No results.'));
|
|
147
|
+
});
|
|
152
148
|
}
|
|
153
149
|
|
|
154
150
|
renderLoadingError() {
|
|
@@ -23,11 +23,7 @@ import { Flex } from '@instructure/ui-flex';
|
|
|
23
23
|
import { Text } from '@instructure/ui-text';
|
|
24
24
|
import { Link } from '@instructure/ui-link';
|
|
25
25
|
import formatMessage from '../../../../format-message';
|
|
26
|
-
import { getIcon } from '../../shared/linkUtils';
|
|
27
|
-
|
|
28
|
-
const {
|
|
29
|
-
Item: FlexItem
|
|
30
|
-
} = Flex;
|
|
26
|
+
import { getIcon } from '../../shared/linkUtils';
|
|
31
27
|
export function buildUrl(contextType, contextId, collectionType) {
|
|
32
28
|
var _typeMap$collectionTy;
|
|
33
29
|
|
|
@@ -72,15 +68,14 @@ export const NoResults = _ref => {
|
|
|
72
68
|
justifyItems: "center",
|
|
73
69
|
alignItems: "center",
|
|
74
70
|
direction: "column"
|
|
75
|
-
}, /*#__PURE__*/React.createElement(
|
|
71
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Icon, {
|
|
76
72
|
size: "large",
|
|
77
73
|
color: "secondary",
|
|
78
74
|
padding: "large"
|
|
79
|
-
})), /*#__PURE__*/React.createElement(
|
|
75
|
+
})), /*#__PURE__*/React.createElement(Flex.Item, {
|
|
80
76
|
margin: "small 0 0"
|
|
81
|
-
}, /*#__PURE__*/React.createElement(Text, null, getMessage(collectionType, isSearchResult))), !isSearchResult && /*#__PURE__*/React.createElement(
|
|
82
|
-
href: buildUrl(contextType, contextId, collectionType)
|
|
83
|
-
,
|
|
77
|
+
}, /*#__PURE__*/React.createElement(Text, null, getMessage(collectionType, isSearchResult))), !isSearchResult && /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Link, {
|
|
78
|
+
href: buildUrl(contextType, contextId, collectionType),
|
|
84
79
|
target: "_blank"
|
|
85
80
|
}, formatMessage('Add one!')))));
|
|
86
81
|
};
|
|
@@ -68,20 +68,14 @@ import bridge from '../../../bridge';
|
|
|
68
68
|
import { getAnchorElement, isOKToLink } from '../../contentInsertionUtils';
|
|
69
69
|
import LinkOptionsTrayController from './components/LinkOptionsTray/LinkOptionsTrayController';
|
|
70
70
|
import { CREATE_LINK, EDIT_LINK } from './components/LinkOptionsDialog/LinkOptionsDialogController';
|
|
71
|
-
import RCEGlobals from '../../RCEGlobals';
|
|
72
71
|
import tinymce from 'tinymce';
|
|
73
72
|
const trayController = new LinkOptionsTrayController();
|
|
74
73
|
const COURSE_PLUGIN_KEY = 'course_links';
|
|
75
74
|
const GROUP_PLUGIN_KEY = 'group_links';
|
|
76
75
|
|
|
77
76
|
function getCommandName(selectedNode) {
|
|
78
|
-
var _RCEGlobals$getFeatur;
|
|
79
|
-
|
|
80
|
-
// show the Course Tray if it's a course link and the ux improvement flag is on,
|
|
81
|
-
// otherwise show the default Link Tray
|
|
82
|
-
const showCourseLinkTray = !!((_RCEGlobals$getFeatur = RCEGlobals.getFeatures()) !== null && _RCEGlobals$getFeatur !== void 0 && _RCEGlobals$getFeatur.rce_ux_improvements);
|
|
83
77
|
const isCourseLink = selectedNode.getAttribute('data-course-type');
|
|
84
|
-
return
|
|
78
|
+
return isCourseLink ? 'instructureTrayForCourseLinks' : 'instructureTrayToEditLink';
|
|
85
79
|
}
|
|
86
80
|
|
|
87
81
|
function selectedAnchorCount(ed) {
|
|
@@ -31,7 +31,6 @@ import { ExternalToolDialogTray } from './ExternalToolDialogTray';
|
|
|
31
31
|
import { ExternalToolDialogModal } from './ExternalToolDialogModal';
|
|
32
32
|
import { showFlashAlert } from '../../../../../common/FlashAlert';
|
|
33
33
|
import { parseUrlOrNull } from '../../../../../util/url-util';
|
|
34
|
-
const FlexItem = Flex.Item;
|
|
35
34
|
export default class ExternalToolDialog extends React.Component {
|
|
36
35
|
constructor() {
|
|
37
36
|
super(...arguments);
|
|
@@ -246,7 +245,7 @@ export default class ExternalToolDialog extends React.Component {
|
|
|
246
245
|
}, formatMessage('The following content is partner provided'))), !state.iframeLoaded && /*#__PURE__*/React.createElement(Flex, {
|
|
247
246
|
alignItems: "center",
|
|
248
247
|
justifyItems: "center"
|
|
249
|
-
}, /*#__PURE__*/React.createElement(
|
|
248
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Spinner, {
|
|
250
249
|
renderTitle: formatMessage('Loading External Tool'),
|
|
251
250
|
size: "large",
|
|
252
251
|
margin: "0 0 0 medium"
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import _pt from "prop-types";
|
|
2
|
+
|
|
1
3
|
/*
|
|
2
4
|
* Copyright (C) 2019 - present Instructure, Inc.
|
|
3
5
|
*
|
|
@@ -16,14 +18,12 @@
|
|
|
16
18
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
19
|
*/
|
|
18
20
|
import React from 'react';
|
|
19
|
-
import PropTypes from 'prop-types';
|
|
20
21
|
import { Tray } from '@instructure/ui-tray';
|
|
21
22
|
import { View } from '@instructure/ui-view';
|
|
22
23
|
import { Flex } from '@instructure/ui-flex';
|
|
23
24
|
import { Heading } from '@instructure/ui-heading';
|
|
24
25
|
import { CloseButton } from '@instructure/ui-buttons';
|
|
25
26
|
import formatMessage from 'format-message';
|
|
26
|
-
const FlexItem = Flex.Item;
|
|
27
27
|
export function ExternalToolDialogTray(props) {
|
|
28
28
|
const {
|
|
29
29
|
label,
|
|
@@ -56,9 +56,9 @@ export function ExternalToolDialogTray(props) {
|
|
|
56
56
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
57
57
|
as: "div",
|
|
58
58
|
padding: "small"
|
|
59
|
-
}, /*#__PURE__*/React.createElement(
|
|
59
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
60
60
|
shouldGrow: true
|
|
61
|
-
}, /*#__PURE__*/React.createElement(Heading, null, name)), /*#__PURE__*/React.createElement(
|
|
61
|
+
}, /*#__PURE__*/React.createElement(Heading, null, name)), /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(CloseButton, {
|
|
62
62
|
onClick: onCloseButton,
|
|
63
63
|
size: "small",
|
|
64
64
|
screenReaderLabel: formatMessage('Close')
|
|
@@ -74,12 +74,6 @@ export function ExternalToolDialogTray(props) {
|
|
|
74
74
|
}, children)))));
|
|
75
75
|
}
|
|
76
76
|
ExternalToolDialogTray.propTypes = {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
mountNode: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
|
|
80
|
-
onOpen: PropTypes.func,
|
|
81
|
-
onClose: PropTypes.func,
|
|
82
|
-
onCloseButton: PropTypes.func,
|
|
83
|
-
name: PropTypes.string.isRequired,
|
|
84
|
-
children: PropTypes.node
|
|
77
|
+
onCloseButton: _pt.func,
|
|
78
|
+
name: _pt.string.isRequired
|
|
85
79
|
};
|
|
@@ -70,7 +70,7 @@ export function ExternalToolSelectionDialog(props) {
|
|
|
70
70
|
"data-mce-component": true,
|
|
71
71
|
liveRegion: getLiveRegion,
|
|
72
72
|
size: "medium",
|
|
73
|
-
|
|
73
|
+
themeOverride: {
|
|
74
74
|
mediumMaxWidth: '42rem'
|
|
75
75
|
},
|
|
76
76
|
label: formatMessage('Apps'),
|
|
@@ -79,7 +79,7 @@ export function ExternalToolSelectionDialog(props) {
|
|
|
79
79
|
open: true,
|
|
80
80
|
shouldCloseOnDocumentClick: false
|
|
81
81
|
}, /*#__PURE__*/React.createElement(Modal.Header, {
|
|
82
|
-
|
|
82
|
+
themeOverride: {
|
|
83
83
|
padding: '0.5rem'
|
|
84
84
|
}
|
|
85
85
|
}, /*#__PURE__*/React.createElement(CloseButton, {
|
|
@@ -35,7 +35,7 @@ export default class ResourceLinkContentItem extends BaseLinkContentItem {
|
|
|
35
35
|
|
|
36
36
|
buildUrl() {
|
|
37
37
|
return addQueryParamsToUrl(this.context.ltiEndpoint, {
|
|
38
|
-
display: '
|
|
38
|
+
display: 'in_rce',
|
|
39
39
|
resource_link_lookup_uuid: this.lookup_uuid,
|
|
40
40
|
[PARENT_FRAME_CONTEXT_PARAM]: this.context.containingCanvasLtiToolId
|
|
41
41
|
});
|
|
@@ -146,7 +146,7 @@ export default class TrayController {
|
|
|
146
146
|
// If not, we can't update the MediaObject in the canvas db.
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
if (videoOptions.media_object_id && videoOptions.media_object_id !== 'undefined'
|
|
149
|
+
if (videoOptions.media_object_id && videoOptions.media_object_id !== 'undefined') {
|
|
150
150
|
videoOptions.updateMediaObject(data).then(_r => {
|
|
151
151
|
if (this.$videoContainer && videoOptions.displayAs === 'embed') {
|
|
152
152
|
this.$videoContainer.contentWindow.postMessage({
|
|
@@ -181,10 +181,15 @@ export default class TrayController {
|
|
|
181
181
|
let vo = {};
|
|
182
182
|
|
|
183
183
|
if (this._shouldOpen) {
|
|
184
|
+
/*
|
|
185
|
+
* When the tray is being opened again, it should be rendered fresh
|
|
186
|
+
* (clearing the internal state) so that the currently-selected video can
|
|
187
|
+
* be used for initial video options.
|
|
188
|
+
*/
|
|
184
189
|
this._renderId++;
|
|
190
|
+
vo = asVideoElement(this.$videoContainer) || {};
|
|
185
191
|
}
|
|
186
192
|
|
|
187
|
-
vo = asVideoElement(this.$videoContainer) || {};
|
|
188
193
|
const element = /*#__PURE__*/React.createElement(VideoOptionsTray, {
|
|
189
194
|
id: "video-options-tray",
|
|
190
195
|
key: this._renderId,
|
|
@@ -38,13 +38,10 @@ import DimensionsInput, { useDimensionsState } from '../../shared/DimensionsInpu
|
|
|
38
38
|
import { getTrayHeight } from '../../shared/trayUtils';
|
|
39
39
|
import { instuiPopupMountNode } from '../../../../util/fullscreenHelpers';
|
|
40
40
|
import { parsedStudioOptionsPropType } from '../../shared/StudioLtiSupportUtils';
|
|
41
|
-
import RCEGlobals from '../../../RCEGlobals';
|
|
42
41
|
|
|
43
42
|
const getLiveRegion = () => document.getElementById('flash_screenreader_holder');
|
|
44
43
|
|
|
45
44
|
export default function VideoOptionsTray(_ref) {
|
|
46
|
-
var _RCEGlobals$getConfig;
|
|
47
|
-
|
|
48
45
|
let {
|
|
49
46
|
videoOptions,
|
|
50
47
|
onRequestClose,
|
|
@@ -71,9 +68,7 @@ export default function VideoOptionsTray(_ref) {
|
|
|
71
68
|
const [minWidth] = useState(MIN_WIDTH_VIDEO);
|
|
72
69
|
const [minHeight] = useState(Math.round(videoHeight / videoWidth * MIN_WIDTH_VIDEO));
|
|
73
70
|
const [minPercentage] = useState(MIN_PERCENTAGE);
|
|
74
|
-
const lock_statuses = (_RCEGlobals$getConfig = RCEGlobals.getConfig()) === null || _RCEGlobals$getConfig === void 0 ? void 0 : _RCEGlobals$getConfig.lockedAttachments;
|
|
75
71
|
const isStudio = !!studioOptions;
|
|
76
|
-
const isLocked = !!lock_statuses && !!lock_statuses[videoOptions.attachmentId];
|
|
77
72
|
const showDisplayOptions = !isStudio || studioOptions.convertibleToLink;
|
|
78
73
|
const showSizeControls = !isStudio || studioOptions.resizable;
|
|
79
74
|
const dimensionsState = useDimensionsState(videoOptions, {
|
|
@@ -129,8 +124,7 @@ export default function VideoOptionsTray(_ref) {
|
|
|
129
124
|
appliedWidth,
|
|
130
125
|
displayAs,
|
|
131
126
|
subtitles,
|
|
132
|
-
updateMediaObject
|
|
133
|
-
isLocked
|
|
127
|
+
updateMediaObject
|
|
134
128
|
});
|
|
135
129
|
}
|
|
136
130
|
|
|
@@ -213,7 +207,7 @@ export default function VideoOptionsTray(_ref) {
|
|
|
213
207
|
shouldShrink: true
|
|
214
208
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
215
209
|
direction: "column"
|
|
216
|
-
},
|
|
210
|
+
}, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
217
211
|
padding: "small"
|
|
218
212
|
}, isStudio ? /*#__PURE__*/React.createElement(Flex, {
|
|
219
213
|
direction: "column"
|
|
@@ -272,7 +266,7 @@ export default function VideoOptionsTray(_ref) {
|
|
|
272
266
|
minWidth: minWidth,
|
|
273
267
|
minPercentage: minPercentage,
|
|
274
268
|
hidePercentage: true
|
|
275
|
-
}))), !isStudio &&
|
|
269
|
+
}))), !isStudio && /*#__PURE__*/React.createElement(Flex.Item, {
|
|
276
270
|
padding: "small"
|
|
277
271
|
}, /*#__PURE__*/React.createElement(FormFieldGroup, {
|
|
278
272
|
description: formatMessage('Closed Captions/Subtitles')
|
|
@@ -24,41 +24,33 @@ import { BaseButton, CloseButton } from '@instructure/ui-buttons';
|
|
|
24
24
|
import { Heading } from '@instructure/ui-heading';
|
|
25
25
|
import { Table } from '@instructure/ui-table';
|
|
26
26
|
import formatMessage from '../../../../format-message';
|
|
27
|
-
import { instuiPopupMountNode } from '../../../../util/fullscreenHelpers';
|
|
28
|
-
|
|
29
|
-
const {
|
|
30
|
-
Head,
|
|
31
|
-
Row,
|
|
32
|
-
ColHeader,
|
|
33
|
-
Body,
|
|
34
|
-
Cell
|
|
35
|
-
} = Table;
|
|
27
|
+
import { instuiPopupMountNode } from '../../../../util/fullscreenHelpers';
|
|
36
28
|
|
|
37
29
|
const renderBody = (headers, rows) => {
|
|
38
30
|
return /*#__PURE__*/React.createElement(Table, {
|
|
39
31
|
caption: formatMessage('Word Count')
|
|
40
|
-
}, /*#__PURE__*/React.createElement(Head, null, /*#__PURE__*/React.createElement(Row, null, headers.map(_ref => {
|
|
32
|
+
}, /*#__PURE__*/React.createElement(Table.Head, null, /*#__PURE__*/React.createElement(Table.Row, null, headers.map(_ref => {
|
|
41
33
|
let {
|
|
42
34
|
id,
|
|
43
35
|
getLabel
|
|
44
36
|
} = _ref;
|
|
45
|
-
return /*#__PURE__*/React.createElement(ColHeader, {
|
|
37
|
+
return /*#__PURE__*/React.createElement(Table.ColHeader, {
|
|
46
38
|
key: id,
|
|
47
39
|
id: id
|
|
48
40
|
}, getLabel());
|
|
49
|
-
}))), /*#__PURE__*/React.createElement(Body, null, rows.map(_ref2 => {
|
|
41
|
+
}))), /*#__PURE__*/React.createElement(Table.Body, null, rows.map(_ref2 => {
|
|
50
42
|
let {
|
|
51
43
|
label,
|
|
52
44
|
documentCount,
|
|
53
45
|
selectionCount
|
|
54
46
|
} = _ref2;
|
|
55
|
-
return /*#__PURE__*/React.createElement(Row, {
|
|
47
|
+
return /*#__PURE__*/React.createElement(Table.Row, {
|
|
56
48
|
key: label
|
|
57
|
-
}, /*#__PURE__*/React.createElement(Cell, {
|
|
49
|
+
}, /*#__PURE__*/React.createElement(Table.Cell, {
|
|
58
50
|
key: "label"
|
|
59
|
-
}, label), /*#__PURE__*/React.createElement(Cell, {
|
|
51
|
+
}, label), /*#__PURE__*/React.createElement(Table.Cell, {
|
|
60
52
|
key: "document"
|
|
61
|
-
}, documentCount), /*#__PURE__*/React.createElement(Cell, {
|
|
53
|
+
}, documentCount), /*#__PURE__*/React.createElement(Table.Cell, {
|
|
62
54
|
key: "selection"
|
|
63
55
|
}, selectionCount));
|
|
64
56
|
})));
|
|
@@ -241,6 +241,7 @@ export default function CanvasContentTray(props) {
|
|
|
241
241
|
const [hidingTrayOnAction, setHidingTrayOnAction] = useState(true);
|
|
242
242
|
const trayRef = useRef(null);
|
|
243
243
|
const scrollingAreaRef = useRef(null);
|
|
244
|
+
const closeButtonRef = useRef(null);
|
|
244
245
|
const [filterSettings, setFilterSettings] = useFilterSettings();
|
|
245
246
|
const [isEditTray, setIsEditTray] = useState(false);
|
|
246
247
|
const [link, setLink] = useState(null);
|
|
@@ -267,6 +268,8 @@ export default function CanvasContentTray(props) {
|
|
|
267
268
|
useEffect(() => {
|
|
268
269
|
const controller = {
|
|
269
270
|
showTrayForPlugin(plugin) {
|
|
271
|
+
var _closeButtonRef$curre;
|
|
272
|
+
|
|
270
273
|
// increment a counter that's used as the key when rendering
|
|
271
274
|
// this gets us a new instance everytime, which is necessary
|
|
272
275
|
// to get the queries run so we have up to date data.
|
|
@@ -294,6 +297,8 @@ export default function CanvasContentTray(props) {
|
|
|
294
297
|
} else {
|
|
295
298
|
setIsEditTray(false);
|
|
296
299
|
}
|
|
300
|
+
|
|
301
|
+
(_closeButtonRef$curre = closeButtonRef.current) === null || _closeButtonRef$curre === void 0 ? void 0 : _closeButtonRef$curre.focus();
|
|
297
302
|
},
|
|
298
303
|
|
|
299
304
|
hideTray(forceClose) {
|
|
@@ -474,7 +479,8 @@ export default function CanvasContentTray(props) {
|
|
|
474
479
|
offset: "medium",
|
|
475
480
|
onClick: handleDismissTray,
|
|
476
481
|
"data-testid": "CloseButton_ContentTray",
|
|
477
|
-
screenReaderLabel: formatMessage('Close')
|
|
482
|
+
screenReaderLabel: formatMessage('Close'),
|
|
483
|
+
elementRef: el => closeButtonRef.current = el
|
|
478
484
|
})), isEditTray && /*#__PURE__*/React.createElement(LinkDisplay, {
|
|
479
485
|
linkText: linkText,
|
|
480
486
|
placeholderText: (link === null || link === void 0 ? void 0 : link.title) || placeholderText,
|
|
@@ -15,7 +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
|
-
import { parse } from 'url';
|
|
18
|
+
import { format, parse } from 'url';
|
|
19
19
|
import { absoluteToRelativeUrl } from '../../../common/fileUrl';
|
|
20
20
|
import { IconAudioLine, IconDocumentLine, IconMsExcelLine, IconMsPptLine, IconMsWordLine, IconPdfLine, IconVideoLine } from '@instructure/ui-icons';
|
|
21
21
|
import RCEGlobals from '../../RCEGlobals';
|
|
@@ -94,13 +94,21 @@ export function mediaPlayerURLFromFile(file, canvasOrigin) {
|
|
|
94
94
|
const type = content_type.replace(/\/.*$/, '');
|
|
95
95
|
|
|
96
96
|
if ((_RCEGlobals$getFeatur = RCEGlobals.getFeatures()) !== null && _RCEGlobals$getFeatur !== void 0 && _RCEGlobals$getFeatur.media_links_use_attachment_id && isAudioOrVideo(content_type) && file.id) {
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const url = parse(`/media_attachments_iframe/${file.id}`, true);
|
|
98
|
+
url.query.type = type;
|
|
99
|
+
url.query.embedded = true;
|
|
100
|
+
|
|
101
|
+
if (file.uuid && file.contextType == 'User') {
|
|
102
|
+
url.query.verifier = file.uuid;
|
|
103
|
+
} else if (file.url || file.href) {
|
|
104
|
+
const parsed_url = parse(file.url || file.href, true);
|
|
105
|
+
|
|
106
|
+
if (parsed_url.query.verifier) {
|
|
107
|
+
url.query.verifier = parsed_url.query.verifier;
|
|
108
|
+
}
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
const verifier = parsed_url.query.verifier ? `&verifier=${parsed_url.query.verifier}` : '';
|
|
103
|
-
return `/media_attachments_iframe/${file.id}?type=${type}${verifier}&embedded=true`;
|
|
111
|
+
return format(url);
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
if (file.embedded_iframe_url) {
|