@instructure/canvas-rce 7.3.1 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/{es/rce/plugins/shared/ai_tools/index.js → __mocks__/@instructure/ui-media-player/_mockUiMediaPlayer.js} +4 -4
- package/__tests__/common/mimeClass.test.js +25 -1
- package/__tests__/rcs/api.test.js +280 -251
- package/es/canvasFileBrowser/FileBrowser.d.ts +2 -2
- package/es/canvasFileBrowser/FileBrowser.js +8 -7
- package/es/common/mimeClass.js +3 -1
- package/es/defaultTinymceConfig.js +47 -49
- package/es/enhance-user-content/enhance_user_content.js +6 -8
- package/es/enhance-user-content/index.d.ts +3 -1
- package/es/enhance-user-content/index.js +3 -1
- package/es/enhance-user-content/youtube_overlay.js +18 -0
- package/es/getThemeVars.d.ts +1 -1
- package/es/getThemeVars.js +23 -26
- package/es/rce/KeyboardShortcutModal.js +1 -1
- package/es/rce/RCE.d.ts +9 -0
- package/es/rce/RCE.js +4 -0
- package/es/rce/RCEGlobals.d.ts +2 -0
- package/es/rce/RCEGlobals.js +1 -0
- package/es/rce/RCEVariants.d.ts +1 -2
- package/es/rce/RCEVariants.js +1 -2
- package/es/rce/RCEWrapper.d.ts +6 -16
- package/es/rce/RCEWrapper.js +18 -87
- package/es/rce/RCEWrapper.utils.d.ts +1 -1
- package/es/rce/RCEWrapperProps.d.ts +2 -1
- package/es/rce/RCEWrapperProps.js +2 -1
- package/es/rce/StatusBar.d.ts +0 -1
- package/es/rce/StatusBar.js +3 -28
- package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.d.ts +2 -1
- package/es/rce/plugins/instructure_equation/EquationEditorModal/advancedOnlySyntax.js +3 -1
- package/es/rce/plugins/instructure_equation/EquationEditorModal/index.d.ts +1 -0
- package/es/rce/plugins/instructure_equation/EquationEditorModal/index.js +12 -2
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageOptions.js +2 -2
- package/es/rce/plugins/instructure_icon_maker/components/CreateIconMakerForm/ImageSection/ImageSection.js +3 -3
- package/es/rce/plugins/instructure_icon_maker/svg/constants.d.ts +20 -5
- package/es/rce/plugins/instructure_icon_maker/svg/utils.d.ts +1 -1
- package/es/rce/plugins/instructure_icon_maker/utils/IconMakerFormHasChanges.js +2 -2
- package/es/rce/plugins/instructure_image/ImageEmbedOptions.d.ts +0 -2
- package/es/rce/plugins/instructure_image/ImageEmbedOptions.js +2 -9
- package/es/rce/plugins/instructure_paste/plugin.js +18 -12
- package/es/rce/plugins/instructure_rce_external_tools/components/ExternalToolDialog/ExternalToolDialogModal.d.ts +1 -1
- package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.d.ts +4 -0
- package/es/rce/plugins/instructure_rce_external_tools/components/util/ToolLaunchIframe.js +4 -0
- package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.d.ts +11 -2
- package/es/rce/plugins/instructure_record/AudioOptionsTray/TrayController.js +92 -10
- package/es/rce/plugins/instructure_record/AudioOptionsTray/index.d.ts +13 -1
- package/es/rce/plugins/instructure_record/AudioOptionsTray/index.js +216 -24
- package/es/rce/plugins/instructure_record/MediaPanel/index.js +16 -5
- package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.d.ts +14 -13
- package/es/rce/plugins/instructure_record/VideoOptionsTray/TrayController.js +110 -39
- package/es/rce/plugins/instructure_record/VideoOptionsTray/index.d.ts +11 -1
- package/es/rce/plugins/instructure_record/VideoOptionsTray/index.js +242 -67
- package/es/rce/plugins/instructure_record/clickCallback.js +19 -4
- package/es/rce/plugins/instructure_record/mediaTranslations.js +1 -1
- package/es/rce/plugins/instructure_record/playerLayoutOptions.d.ts +25 -0
- package/es/rce/plugins/instructure_record/playerLayoutOptions.js +91 -0
- package/es/rce/plugins/instructure_record/plugin.js +2 -5
- package/es/rce/plugins/instructure_record/utils.d.ts +3 -0
- package/es/rce/plugins/instructure_record/utils.js +31 -0
- package/es/rce/plugins/instructure_studio_media_options/plugin.js +82 -26
- package/es/rce/plugins/shared/ContentSelection.d.ts +6 -1
- package/es/rce/plugins/shared/ContentSelection.js +15 -6
- package/es/rce/plugins/shared/DimensionsInput/DimensionInput.js +1 -2
- package/es/rce/plugins/shared/DimensionsInput/index.js +11 -12
- package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.d.ts +1 -1
- package/es/rce/plugins/shared/DimensionsInput/useDimensionsState.js +4 -3
- package/es/rce/plugins/shared/StudioLtiSupportUtils.d.ts +27 -6
- package/es/rce/plugins/shared/StudioLtiSupportUtils.js +82 -13
- package/es/rce/plugins/shared/Upload/UploadFile.js +1 -8
- package/es/rce/style.d.ts +2 -1
- package/es/rce/style.js +4 -2
- package/es/rcs/api.d.ts +5 -10
- package/es/rcs/api.js +15 -21
- package/es/rcs/fake.d.ts +1 -7
- package/es/rcs/fake.js +1 -47
- package/es/sidebar/actions/media.d.ts +19 -6
- package/es/sidebar/actions/media.js +17 -4
- package/es/sidebar/actions/upload.d.ts +3 -3
- package/es/sidebar/actions/upload.js +9 -9
- package/es/sidebar/containers/Sidebar.js +0 -2
- package/es/sidebar/containers/sidebarHandlers.d.ts +2 -4
- package/es/sidebar/containers/sidebarHandlers.js +2 -5
- package/es/sidebar/reducers/index.d.ts +0 -1
- package/es/sidebar/reducers/index.js +0 -2
- package/es/sidebar/store/initialState.d.ts +0 -1
- package/es/sidebar/store/initialState.js +0 -5
- package/es/translations/locales/ar.js +65 -80
- package/es/translations/locales/ca.js +65 -80
- package/es/translations/locales/cy.js +65 -80
- package/es/translations/locales/da-x-k12.js +65 -80
- package/es/translations/locales/da.js +65 -80
- package/es/translations/locales/de.js +65 -80
- package/es/translations/locales/el.js +0 -9
- package/es/translations/locales/en-AU-x-unimelb.js +65 -80
- package/es/translations/locales/en-GB-x-ukhe.js +65 -80
- package/es/translations/locales/en.js +61 -79
- package/es/translations/locales/en_AU.js +65 -80
- package/es/translations/locales/en_CA.js +65 -80
- package/es/translations/locales/en_CY.js +65 -80
- package/es/translations/locales/en_GB.js +65 -80
- package/es/translations/locales/es.js +65 -80
- package/es/translations/locales/es_ES.js +65 -80
- package/es/translations/locales/fa_IR.js +0 -9
- package/es/translations/locales/fi.js +65 -80
- package/es/translations/locales/fr.js +65 -80
- package/es/translations/locales/fr_CA.js +65 -80
- package/es/translations/locales/ga.js +65 -80
- package/es/translations/locales/he.js +0 -9
- package/es/translations/locales/hi.js +65 -80
- package/es/translations/locales/ht.js +65 -80
- package/es/translations/locales/hu.js +0 -36
- package/es/translations/locales/hy.js +0 -9
- package/es/translations/locales/id.js +65 -80
- package/es/translations/locales/is.js +65 -80
- package/es/translations/locales/it.js +65 -80
- package/es/translations/locales/ja.js +65 -80
- package/es/translations/locales/ko.js +2455 -133
- package/es/translations/locales/mi.js +65 -80
- package/es/translations/locales/ms.js +65 -80
- package/es/translations/locales/nb-x-k12.js +65 -80
- package/es/translations/locales/nb.js +65 -80
- package/es/translations/locales/nl.js +66 -81
- package/es/translations/locales/nn.js +0 -36
- package/es/translations/locales/pl.js +65 -80
- package/es/translations/locales/pt.js +65 -80
- package/es/translations/locales/pt_BR.js +65 -80
- package/es/translations/locales/ru.js +65 -80
- package/es/translations/locales/sl.js +65 -80
- package/es/translations/locales/sv-x-k12.js +65 -80
- package/es/translations/locales/sv.js +65 -80
- package/es/translations/locales/th.js +65 -80
- package/es/translations/locales/tr.js +1962 -18
- package/es/translations/locales/uk_UA.js +0 -9
- package/es/translations/locales/vi.js +65 -80
- package/es/translations/locales/zh-Hans.js +65 -80
- package/es/translations/locales/zh-Hant.js +65 -80
- package/es/translations/locales/zh.js +65 -80
- package/es/translations/locales/zh_HK.js +65 -80
- package/eslint.config.js +16 -147
- package/jest/jest-setup.js +1 -0
- package/jest.config.js +2 -0
- package/oxlint.json +84 -0
- package/package.json +86 -62
- package/tsconfig.json +3 -2
- package/es/rce/plugins/shared/ai_tools/AIResponseModal.d.ts +0 -10
- package/es/rce/plugins/shared/ai_tools/AIResponseModal.js +0 -67
- package/es/rce/plugins/shared/ai_tools/AIToolsTray.d.ts +0 -18
- package/es/rce/plugins/shared/ai_tools/AIToolsTray.js +0 -489
- package/es/rce/plugins/shared/ai_tools/aiicons.d.ts +0 -7
- package/es/rce/plugins/shared/ai_tools/aiicons.js +0 -60
- package/es/rce/plugins/shared/ai_tools/index.d.ts +0 -3
- package/es/sidebar/actions/flickr.d.ts +0 -20
- package/es/sidebar/actions/flickr.js +0 -60
- package/es/sidebar/reducers/flickr.d.ts +0 -1
- package/es/sidebar/reducers/flickr.js +0 -49
|
@@ -4,14 +4,23 @@ export default class TrayController {
|
|
|
4
4
|
_shouldOpen: boolean;
|
|
5
5
|
_editor: any;
|
|
6
6
|
_audioContainer: Element | null;
|
|
7
|
+
_captionsModified: boolean;
|
|
8
|
+
requestSubtitlesFromIframe(cb: any): void;
|
|
7
9
|
get container(): HTMLElement;
|
|
8
10
|
get isOpen(): boolean;
|
|
9
11
|
showTrayForEditor(editor: any): void;
|
|
12
|
+
_isPlayerReady: boolean | undefined;
|
|
10
13
|
hideTrayForEditor(editor: any): void;
|
|
14
|
+
_listenForPlayerIframeToLoad(currentMediaId: any): void;
|
|
15
|
+
_iframeLoadingListener: AbortController | undefined;
|
|
16
|
+
_reloadAudioPlayer(): void;
|
|
11
17
|
_dismissTray(): void;
|
|
12
18
|
_resetController(): Node;
|
|
19
|
+
_resizeContainer({ height, width }: {
|
|
20
|
+
height: any;
|
|
21
|
+
width: any;
|
|
22
|
+
}): void;
|
|
13
23
|
_applyAudioOptions(audioOptions: any): any;
|
|
14
|
-
requestSubtitlesFromIframe(cb: any): void;
|
|
15
24
|
_subtitleListener: AbortController | undefined;
|
|
16
|
-
_renderTray(
|
|
25
|
+
_renderTray(): void;
|
|
17
26
|
}
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
import React from 'react';
|
|
20
20
|
import ReactDOM from 'react-dom';
|
|
21
21
|
import bridge from '../../../../bridge';
|
|
22
|
+
import { showFlashAlert } from '../../../../common/FlashAlert';
|
|
23
|
+
import formatMessage from '../../../../format-message';
|
|
24
|
+
import RCEGlobals from '../../../RCEGlobals';
|
|
22
25
|
import { asAudioElement } from '../../shared/ContentSelection';
|
|
23
26
|
import { findMediaPlayerIframe } from '../../shared/iframeUtils';
|
|
24
27
|
import AudioOptionsTray from '.';
|
|
@@ -29,6 +32,8 @@ export default class TrayController {
|
|
|
29
32
|
this._shouldOpen = false;
|
|
30
33
|
this._editor = null;
|
|
31
34
|
this._audioContainer = null;
|
|
35
|
+
this._captionsModified = false;
|
|
36
|
+
this.requestSubtitlesFromIframe = this.requestSubtitlesFromIframe.bind(this);
|
|
32
37
|
}
|
|
33
38
|
get container() {
|
|
34
39
|
let _container = document.getElementById(CONTAINER_ID);
|
|
@@ -46,19 +51,57 @@ export default class TrayController {
|
|
|
46
51
|
this._shouldOpen = true;
|
|
47
52
|
this._editor = editor;
|
|
48
53
|
this._audioContainer = findMediaPlayerIframe(editor.selection.getNode());
|
|
54
|
+
this._captionsModified = false;
|
|
55
|
+
this._isPlayerReady = false;
|
|
49
56
|
if (bridge.focusedEditor) {
|
|
50
57
|
// Dismiss any content trays that may already be open
|
|
51
58
|
bridge.hideTrays();
|
|
52
59
|
}
|
|
53
|
-
|
|
54
|
-
this.
|
|
60
|
+
this._renderTray();
|
|
61
|
+
const audioOptions = asAudioElement(this._audioContainer);
|
|
62
|
+
// Clean broadcast listeners for any existing trays which are not shown (if not cleaned automatically)
|
|
63
|
+
this._iframeLoadingListener?.abort();
|
|
64
|
+
this._listenForPlayerIframeToLoad(audioOptions.id);
|
|
55
65
|
}
|
|
56
66
|
hideTrayForEditor(editor) {
|
|
57
67
|
if (this._editor === editor) {
|
|
58
68
|
this._dismissTray();
|
|
59
69
|
}
|
|
60
70
|
}
|
|
71
|
+
_listenForPlayerIframeToLoad(currentMediaId) {
|
|
72
|
+
if (!bridge.canvasOrigin) return;
|
|
73
|
+
this._iframeLoadingListener = new AbortController();
|
|
74
|
+
|
|
75
|
+
// Wait for player iframe to be loaded
|
|
76
|
+
window.addEventListener('message', event => {
|
|
77
|
+
// If tray was opened before player iframe was ready it will catch ready event.
|
|
78
|
+
// If not it will request it later and catch it here anyway.
|
|
79
|
+
if (event.data?.subject === 'media_player.iframe_ready' && event.data?.mediaId === currentMediaId) {
|
|
80
|
+
this._iframeLoadingListener.abort();
|
|
81
|
+
this._isPlayerReady = true;
|
|
82
|
+
this._renderTray();
|
|
83
|
+
}
|
|
84
|
+
}, {
|
|
85
|
+
signal: this._iframeLoadingListener.signal
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// If tray was opened after player was loaded we need to request iframe_ready state
|
|
89
|
+
this._audioContainer?.contentWindow?.postMessage({
|
|
90
|
+
subject: 'media_player.get_ready_state'
|
|
91
|
+
}, bridge.canvasOrigin);
|
|
92
|
+
}
|
|
93
|
+
_reloadAudioPlayer() {
|
|
94
|
+
if (this._audioContainer?.contentWindow?.location) {
|
|
95
|
+
this._audioContainer.contentWindow.location.reload();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
61
98
|
_dismissTray() {
|
|
99
|
+
const isCaptionImprovements = RCEGlobals.getFeatures()?.rce_asr_captioning_improvements || false;
|
|
100
|
+
|
|
101
|
+
// Reload if captions were modified AND feature flag enabled
|
|
102
|
+
if (isCaptionImprovements && this._captionsModified && this._audioContainer) {
|
|
103
|
+
this._reloadAudioPlayer();
|
|
104
|
+
}
|
|
62
105
|
if (this._audioContainer) {
|
|
63
106
|
this._editor.selection.select(this._audioContainer);
|
|
64
107
|
}
|
|
@@ -66,24 +109,50 @@ export default class TrayController {
|
|
|
66
109
|
}
|
|
67
110
|
_resetController() {
|
|
68
111
|
this._shouldOpen = false;
|
|
69
|
-
|
|
70
|
-
this._renderTray(trayProps);
|
|
112
|
+
this._renderTray();
|
|
71
113
|
this._editor = null;
|
|
72
114
|
this._audioContainer = null;
|
|
115
|
+
this._iframeLoadingListener?.abort();
|
|
73
116
|
const elem = document.getElementById(CONTAINER_ID);
|
|
74
117
|
return elem.parentNode.removeChild(elem);
|
|
75
118
|
}
|
|
119
|
+
_resizeContainer({
|
|
120
|
+
height,
|
|
121
|
+
width
|
|
122
|
+
}) {
|
|
123
|
+
const styles = {
|
|
124
|
+
height: `${height}px`,
|
|
125
|
+
width: `${width}px`
|
|
126
|
+
};
|
|
127
|
+
this._editor.dom.setStyles(this._audioContainer.parentElement, styles);
|
|
128
|
+
this._editor.dom.setStyles(this._audioContainer, styles);
|
|
129
|
+
|
|
130
|
+
// tell tinymce so the context toolbar resets
|
|
131
|
+
this._editor.fire('ObjectResized', {
|
|
132
|
+
target: this._audioContainer,
|
|
133
|
+
width: width,
|
|
134
|
+
height: height
|
|
135
|
+
});
|
|
136
|
+
}
|
|
76
137
|
_applyAudioOptions(audioOptions) {
|
|
138
|
+
this._resizeContainer({
|
|
139
|
+
width: audioOptions.appliedWidth,
|
|
140
|
+
height: audioOptions.appliedHeight
|
|
141
|
+
});
|
|
77
142
|
const hasAttachmentId = audioOptions.attachment_id;
|
|
78
143
|
if (!hasAttachmentId && (!audioOptions.media_object_id || audioOptions.media_object_id === 'undefined')) {
|
|
79
144
|
return;
|
|
80
145
|
}
|
|
81
146
|
const container = this._audioContainer;
|
|
82
|
-
|
|
147
|
+
const isCaptionImprovements = RCEGlobals.getFeatures()?.rce_asr_captioning_improvements || false;
|
|
148
|
+
const data = {
|
|
83
149
|
media_object_id: audioOptions.media_object_id,
|
|
150
|
+
attachment_id: audioOptions.attachment_id,
|
|
84
151
|
subtitles: audioOptions.subtitles,
|
|
85
|
-
|
|
86
|
-
|
|
152
|
+
skipCaptionUpdate: isCaptionImprovements,
|
|
153
|
+
viewerRestrictions: audioOptions.viewerRestrictions
|
|
154
|
+
};
|
|
155
|
+
return audioOptions.updateMediaObject(data).then(() => container?.contentWindow.location.reload()).catch(ex => {
|
|
87
156
|
console.error('Failed updating audio captions', ex);
|
|
88
157
|
});
|
|
89
158
|
}
|
|
@@ -101,9 +170,10 @@ export default class TrayController {
|
|
|
101
170
|
subject: 'media_tracks_request'
|
|
102
171
|
}, bridge.canvasOrigin);
|
|
103
172
|
}
|
|
104
|
-
_renderTray(
|
|
173
|
+
_renderTray() {
|
|
105
174
|
const audioOptions = asAudioElement(this._audioContainer) || {};
|
|
106
175
|
const element = /*#__PURE__*/React.createElement(AudioOptionsTray, {
|
|
176
|
+
key: audioOptions.id,
|
|
107
177
|
audioOptions: audioOptions,
|
|
108
178
|
onEntered: () => {
|
|
109
179
|
this._isOpen = true;
|
|
@@ -112,15 +182,27 @@ export default class TrayController {
|
|
|
112
182
|
bridge.focusActiveEditor(false);
|
|
113
183
|
this._isOpen = false;
|
|
114
184
|
this._subtitleListener?.abort();
|
|
185
|
+
this._iframeLoadingListener?.abort();
|
|
186
|
+
this._isPlayerReady = false;
|
|
115
187
|
},
|
|
116
188
|
onSave: options => {
|
|
117
189
|
this._applyAudioOptions(options);
|
|
118
190
|
this._dismissTray();
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
showFlashAlert({
|
|
193
|
+
message: formatMessage('Media options saved.'),
|
|
194
|
+
type: 'success'
|
|
195
|
+
});
|
|
196
|
+
}, 0);
|
|
119
197
|
},
|
|
120
198
|
onDismiss: () => this._dismissTray(),
|
|
199
|
+
onCaptionsModified: () => {
|
|
200
|
+
this._captionsModified = true;
|
|
201
|
+
},
|
|
121
202
|
open: this._shouldOpen,
|
|
122
|
-
trayProps: trayProps,
|
|
123
|
-
requestSubtitlesFromIframe:
|
|
203
|
+
trayProps: bridge.trayProps.get(this._editor),
|
|
204
|
+
requestSubtitlesFromIframe: this.requestSubtitlesFromIframe,
|
|
205
|
+
isLoading: !this._isPlayerReady
|
|
124
206
|
});
|
|
125
207
|
ReactDOM.render(element, this.container);
|
|
126
208
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare function AudioOptionsTray({ open, onEntered, onExited, onDismiss, onSave, trayProps, audioOptions, requestSubtitlesFromIframe, }: {
|
|
1
|
+
declare function AudioOptionsTray({ open, onEntered, onExited, onDismiss, onSave, trayProps, audioOptions, requestSubtitlesFromIframe, onCaptionsModified, isLoading, id, }: {
|
|
2
2
|
open: any;
|
|
3
3
|
onEntered: any;
|
|
4
4
|
onExited: any;
|
|
@@ -7,6 +7,9 @@ declare function AudioOptionsTray({ open, onEntered, onExited, onDismiss, onSave
|
|
|
7
7
|
trayProps: any;
|
|
8
8
|
audioOptions: any;
|
|
9
9
|
requestSubtitlesFromIframe: any;
|
|
10
|
+
onCaptionsModified: any;
|
|
11
|
+
isLoading?: boolean | undefined;
|
|
12
|
+
id?: string | undefined;
|
|
10
13
|
}): React.JSX.Element;
|
|
11
14
|
declare namespace AudioOptionsTray {
|
|
12
15
|
namespace propTypes {
|
|
@@ -26,7 +29,13 @@ declare namespace AudioOptionsTray {
|
|
|
26
29
|
tracks: import("prop-types").Requireable<(import("prop-types").InferProps<{
|
|
27
30
|
locale: import("prop-types").Validator<string>;
|
|
28
31
|
}> | null | undefined)[]>;
|
|
32
|
+
viewerRestrictions: import("prop-types").Requireable<import("prop-types").InferProps<{
|
|
33
|
+
show_rolling_transcript: import("prop-types").Requireable<boolean>;
|
|
34
|
+
}>>;
|
|
29
35
|
}>>>;
|
|
36
|
+
export { func as onCaptionsModified };
|
|
37
|
+
export { bool as isLoading };
|
|
38
|
+
export { string as id };
|
|
30
39
|
}
|
|
31
40
|
namespace defaultProps {
|
|
32
41
|
let onEntered: null;
|
|
@@ -34,8 +43,11 @@ declare namespace AudioOptionsTray {
|
|
|
34
43
|
let onDismiss: null;
|
|
35
44
|
let onSave: null;
|
|
36
45
|
function requestSubtitlesFromIframe(): void;
|
|
46
|
+
let onCaptionsModified: null;
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
export default AudioOptionsTray;
|
|
40
50
|
import React from 'react';
|
|
41
51
|
import { func } from 'prop-types';
|
|
52
|
+
import { bool } from 'prop-types';
|
|
53
|
+
import { string } from 'prop-types';
|
|
@@ -16,20 +16,36 @@
|
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import React, {
|
|
19
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
20
20
|
import { arrayOf, bool, func, shape, string } from 'prop-types';
|
|
21
|
+
import { ClosedCaptionPanel, ClosedCaptionPanelV2, CONSTANTS, trackPendoEvent, AUDIO_PLAYER_SIZE } from '@instructure/canvas-media';
|
|
22
|
+
import { Button, CloseButton } from '@instructure/ui-buttons';
|
|
23
|
+
import { Checkbox, CheckboxGroup } from '@instructure/ui-checkbox';
|
|
21
24
|
import { Flex } from '@instructure/ui-flex';
|
|
22
|
-
import { Tray } from '@instructure/ui-tray';
|
|
23
25
|
import { FormFieldGroup } from '@instructure/ui-form-field';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
26
|
+
import { Heading } from '@instructure/ui-heading';
|
|
27
|
+
import { IconExternalLinkLine } from '@instructure/ui-icons';
|
|
28
|
+
import { Link } from '@instructure/ui-link';
|
|
29
|
+
import { Spinner } from '@instructure/ui-spinner';
|
|
30
|
+
import { Tooltip } from '@instructure/ui-tooltip';
|
|
31
|
+
import { Tray } from '@instructure/ui-tray';
|
|
32
|
+
import { View } from '@instructure/ui-view';
|
|
33
|
+
import { SimpleSelect } from '@instructure/ui-simple-select';
|
|
34
|
+
import { Text } from '@instructure/ui-text';
|
|
27
35
|
import Bridge from '../../../../bridge';
|
|
28
36
|
import formatMessage from '../../../../format-message';
|
|
29
|
-
import
|
|
37
|
+
import RCEGlobals from '../../../../rce/RCEGlobals';
|
|
38
|
+
import RceApiSource, { originFromHost } from '../../../../rcs/api';
|
|
30
39
|
import { instuiPopupMountNodeFn } from '../../../../util/fullscreenHelpers';
|
|
31
|
-
import {
|
|
40
|
+
import { StoreProvider } from '../../shared/StoreContext';
|
|
41
|
+
import { getTrayHeight } from '../../shared/trayUtils';
|
|
42
|
+
import { mapViewerRestrictions, readViewerRestrictions } from '../utils';
|
|
43
|
+
import DimensionsInput, { useDimensionsState } from '../../shared/DimensionsInput';
|
|
44
|
+
import { getPlayerLayoutSizes, labelForPlayerLayoutSize, playerLayoutDimensions, scalePlayerLayoutForHeight, scalePlayerLayoutForWidth } from '../playerLayoutOptions';
|
|
45
|
+
import { CUSTOM, MIN_PERCENTAGE } from '../../instructure_image/ImageEmbedOptions';
|
|
32
46
|
const getLiveRegion = () => document.getElementById('flash_screenreader_holder');
|
|
47
|
+
const MIN_WIDTH = AUDIO_PLAYER_SIZE.width;
|
|
48
|
+
const MIN_HEIGHT = AUDIO_PLAYER_SIZE.height;
|
|
33
49
|
export default function AudioOptionsTray({
|
|
34
50
|
open,
|
|
35
51
|
onEntered,
|
|
@@ -38,20 +54,83 @@ export default function AudioOptionsTray({
|
|
|
38
54
|
onSave,
|
|
39
55
|
trayProps,
|
|
40
56
|
audioOptions,
|
|
41
|
-
requestSubtitlesFromIframe
|
|
57
|
+
requestSubtitlesFromIframe,
|
|
58
|
+
onCaptionsModified,
|
|
59
|
+
isLoading = false,
|
|
60
|
+
id = 'audio-options-tray'
|
|
42
61
|
}) {
|
|
43
62
|
const [subtitles, setSubtitles] = useState(audioOptions.tracks || []);
|
|
63
|
+
const api = new RceApiSource(trayProps);
|
|
64
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
65
|
+
const fetchedFromIframeRef = useRef(false);
|
|
66
|
+
const [viewerRestrictions, setViewerRestrictions] = useState(() => readViewerRestrictions(audioOptions.viewerRestrictions));
|
|
67
|
+
const [sizeKey, setSizeKey] = useState(() => {
|
|
68
|
+
var _match$;
|
|
69
|
+
const match = Object.entries(playerLayoutDimensions).find(([, dims]) => dims.width === audioOptions.containerDimensions.width);
|
|
70
|
+
return (_match$ = match?.[0]) !== null && _match$ !== void 0 ? _match$ : CUSTOM;
|
|
71
|
+
});
|
|
72
|
+
const dimensionsState = useDimensionsState({
|
|
73
|
+
appliedHeight: audioOptions.containerDimensions.height,
|
|
74
|
+
appliedWidth: audioOptions.containerDimensions.width,
|
|
75
|
+
usePercentageUnits: false
|
|
76
|
+
}, {
|
|
77
|
+
minHeight: MIN_HEIGHT,
|
|
78
|
+
minWidth: MIN_WIDTH,
|
|
79
|
+
minPercentage: MIN_PERCENTAGE
|
|
80
|
+
}, {
|
|
81
|
+
scaleFns: {
|
|
82
|
+
width: scalePlayerLayoutForWidth,
|
|
83
|
+
height: scalePlayerLayoutForHeight
|
|
84
|
+
}
|
|
85
|
+
});
|
|
44
86
|
useEffect(() => {
|
|
45
|
-
if (subtitles.length === 0)
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
if (!isLoading && subtitles.length === 0 && !fetchedFromIframeRef.current) {
|
|
88
|
+
// only request subtitle data after mount
|
|
89
|
+
fetchedFromIframeRef.current = true;
|
|
90
|
+
requestSubtitlesFromIframe(setSubtitles);
|
|
91
|
+
}
|
|
92
|
+
}, [isLoading, subtitles.length, requestSubtitlesFromIframe]);
|
|
93
|
+
const isAsrCaptioningImprovements = RCEGlobals.getFeatures()?.rce_asr_captioning_improvements;
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (open && isAsrCaptioningImprovements) {
|
|
96
|
+
trackPendoEvent('canvas_media_options_opened', {
|
|
97
|
+
entry_point: 'quick_menu',
|
|
98
|
+
media_kind: 'audio'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}, [open, isAsrCaptioningImprovements]);
|
|
102
|
+
const handleUpdateSubtitles = newSubtitles => {
|
|
103
|
+
setSubtitles(newSubtitles);
|
|
104
|
+
};
|
|
105
|
+
const handleSave = (_e, contentProps) => {
|
|
48
106
|
onSave({
|
|
49
107
|
media_object_id: audioOptions.id,
|
|
50
108
|
subtitles,
|
|
51
109
|
attachment_id: audioOptions.attachmentId,
|
|
52
|
-
updateMediaObject: contentProps.updateMediaObject
|
|
110
|
+
updateMediaObject: contentProps.updateMediaObject,
|
|
111
|
+
viewerRestrictions: mapViewerRestrictions(viewerRestrictions),
|
|
112
|
+
appliedHeight: sizeKey === CUSTOM ? dimensionsState.height : playerLayoutDimensions[sizeKey].height,
|
|
113
|
+
appliedWidth: sizeKey === CUSTOM ? dimensionsState.width : playerLayoutDimensions[sizeKey].width
|
|
53
114
|
});
|
|
54
115
|
};
|
|
116
|
+
const handleDirtyCheck = isDirty => {
|
|
117
|
+
setHasUnsavedChanges(isDirty);
|
|
118
|
+
};
|
|
119
|
+
const handleSizeChange = (_event, selectedOption) => {
|
|
120
|
+
setSizeKey(selectedOption.value);
|
|
121
|
+
};
|
|
122
|
+
const showSizeControls = isAsrCaptioningImprovements;
|
|
123
|
+
const applyDescribedBy = useCallback(playerLayoutInput => {
|
|
124
|
+
if (isAsrCaptioningImprovements && playerLayoutInput) {
|
|
125
|
+
const helperId = `${id}-size-helper-text`;
|
|
126
|
+
const existing = playerLayoutInput.getAttribute('aria-describedby') || '';
|
|
127
|
+
const ids = existing.split(' ').filter(Boolean);
|
|
128
|
+
if (!ids.includes(helperId)) {
|
|
129
|
+
playerLayoutInput.setAttribute('aria-describedby', [...ids, helperId].join(' '));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, [isAsrCaptioningImprovements, id]);
|
|
133
|
+
const saveDisabled = sizeKey === CUSTOM && !dimensionsState.isValid;
|
|
55
134
|
return /*#__PURE__*/React.createElement(StoreProvider, trayProps, contentProps => /*#__PURE__*/React.createElement(Tray, {
|
|
56
135
|
key: "audio-options-tray",
|
|
57
136
|
"data-mce-component": true,
|
|
@@ -64,7 +143,8 @@ export default function AudioOptionsTray({
|
|
|
64
143
|
placement: "end",
|
|
65
144
|
shouldCloseOnDocumentClick: true,
|
|
66
145
|
shouldContainFocus: true,
|
|
67
|
-
shouldReturnFocus: true
|
|
146
|
+
shouldReturnFocus: true,
|
|
147
|
+
size: isAsrCaptioningImprovements ? 'regular' : 'small'
|
|
68
148
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
69
149
|
direction: "column",
|
|
70
150
|
height: getTrayHeight()
|
|
@@ -83,7 +163,13 @@ export default function AudioOptionsTray({
|
|
|
83
163
|
color: "primary",
|
|
84
164
|
onClick: onDismiss,
|
|
85
165
|
screenReaderLabel: formatMessage('Close')
|
|
86
|
-
})))), /*#__PURE__*/React.createElement(Flex.Item, {
|
|
166
|
+
})))), isLoading ? /*#__PURE__*/React.createElement(Flex.Item, {
|
|
167
|
+
textAlign: "center",
|
|
168
|
+
margin: "xx-large",
|
|
169
|
+
padding: "xx-large"
|
|
170
|
+
}, /*#__PURE__*/React.createElement(Spinner, {
|
|
171
|
+
renderTitle: formatMessage('Loading')
|
|
172
|
+
})) : /*#__PURE__*/React.createElement(Flex.Item, {
|
|
87
173
|
as: "form",
|
|
88
174
|
shouldGrow: true,
|
|
89
175
|
margin: "none",
|
|
@@ -98,30 +184,129 @@ export default function AudioOptionsTray({
|
|
|
98
184
|
shouldShrink: true
|
|
99
185
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
100
186
|
direction: "column"
|
|
101
|
-
}, /*#__PURE__*/React.createElement(Flex.Item, {
|
|
187
|
+
}, showSizeControls && /*#__PURE__*/React.createElement(Flex.Item, {
|
|
188
|
+
margin: "small none xx-small none"
|
|
189
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
190
|
+
as: "div",
|
|
191
|
+
padding: "small small xx-small small"
|
|
192
|
+
}, /*#__PURE__*/React.createElement(SimpleSelect, {
|
|
193
|
+
inputRef: applyDescribedBy,
|
|
194
|
+
id: `${id}-size`,
|
|
195
|
+
mountNode: instuiPopupMountNodeFn,
|
|
196
|
+
renderLabel: formatMessage('Player layout'),
|
|
197
|
+
assistiveText: formatMessage('Use arrow keys to navigate options.'),
|
|
198
|
+
onChange: handleSizeChange,
|
|
199
|
+
value: sizeKey
|
|
200
|
+
}, getPlayerLayoutSizes().map(size => /*#__PURE__*/React.createElement(SimpleSelect.Option, {
|
|
201
|
+
id: `${id}-size-${size}`,
|
|
202
|
+
key: size,
|
|
203
|
+
value: size
|
|
204
|
+
}, labelForPlayerLayoutSize(size)))), /*#__PURE__*/React.createElement(View, {
|
|
205
|
+
as: "div",
|
|
206
|
+
id: `${id}-size-helper-text`,
|
|
207
|
+
margin: "xx-small none none none"
|
|
208
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
209
|
+
size: "small"
|
|
210
|
+
}, formatMessage('Transcript panel is available at widths above 720px.')))), sizeKey === CUSTOM && /*#__PURE__*/React.createElement(View, {
|
|
211
|
+
as: "div",
|
|
212
|
+
padding: "xx-small small"
|
|
213
|
+
}, /*#__PURE__*/React.createElement(DimensionsInput, {
|
|
214
|
+
dimensionsState: dimensionsState,
|
|
215
|
+
minHeight: MIN_HEIGHT,
|
|
216
|
+
minWidth: MIN_WIDTH,
|
|
217
|
+
minPercentage: MIN_PERCENTAGE,
|
|
218
|
+
hidePercentage: true
|
|
219
|
+
}))), isAsrCaptioningImprovements && /*#__PURE__*/React.createElement(Flex.Item, {
|
|
220
|
+
padding: "small"
|
|
221
|
+
}, /*#__PURE__*/React.createElement(CheckboxGroup, {
|
|
222
|
+
name: "viewer-restrictions",
|
|
223
|
+
onChange: setViewerRestrictions,
|
|
224
|
+
defaultValue: viewerRestrictions,
|
|
225
|
+
description: /*#__PURE__*/React.createElement(Heading, {
|
|
226
|
+
level: "h4",
|
|
227
|
+
as: "h3"
|
|
228
|
+
}, formatMessage('Viewer Restrictions'))
|
|
229
|
+
}, /*#__PURE__*/React.createElement(Checkbox, {
|
|
230
|
+
variant: "toggle",
|
|
231
|
+
label: formatMessage('Show Rolling Transcript'),
|
|
232
|
+
value: "show_rolling_transcript"
|
|
233
|
+
}))), /*#__PURE__*/React.createElement(Flex.Item, {
|
|
102
234
|
padding: "small"
|
|
103
235
|
}, /*#__PURE__*/React.createElement(FormFieldGroup, {
|
|
104
|
-
description:
|
|
105
|
-
|
|
236
|
+
description: /*#__PURE__*/React.createElement(Heading, {
|
|
237
|
+
level: "h4",
|
|
238
|
+
as: "h3"
|
|
239
|
+
}, formatMessage('Closed Captions/Subtitles'))
|
|
240
|
+
}, !isAsrCaptioningImprovements ? /*#__PURE__*/React.createElement(ClosedCaptionPanel, {
|
|
241
|
+
key: subtitles.reduce((acc, track) => acc + track.locale, ''),
|
|
106
242
|
subtitles: subtitles.map(st => ({
|
|
107
243
|
locale: st.locale,
|
|
108
244
|
file: {
|
|
109
245
|
name: st.language || st.locale
|
|
110
|
-
}
|
|
246
|
+
},
|
|
247
|
+
asr: Boolean(st.asr)
|
|
111
248
|
})),
|
|
112
249
|
uploadMediaTranslations: Bridge.uploadMediaTranslations,
|
|
113
250
|
languages: Bridge.languages,
|
|
114
251
|
updateSubtitles: newSubtitles => setSubtitles(newSubtitles),
|
|
115
252
|
liveRegion: getLiveRegion
|
|
116
|
-
})
|
|
253
|
+
}) : /*#__PURE__*/React.createElement(ClosedCaptionPanelV2, {
|
|
254
|
+
subtitles: subtitles.map(st => ({
|
|
255
|
+
...st,
|
|
256
|
+
file: {
|
|
257
|
+
name: st.language || st.locale
|
|
258
|
+
},
|
|
259
|
+
asr: Boolean(st.asr)
|
|
260
|
+
})),
|
|
261
|
+
languages: Bridge.languages,
|
|
262
|
+
userLocale: Bridge.userLocale,
|
|
263
|
+
onUpdateSubtitles: handleUpdateSubtitles,
|
|
264
|
+
liveRegion: getLiveRegion,
|
|
265
|
+
mountNode: instuiPopupMountNodeFn,
|
|
266
|
+
uploadConfig: {
|
|
267
|
+
mediaObjectId: audioOptions.id,
|
|
268
|
+
attachmentId: audioOptions.attachmentId,
|
|
269
|
+
origin: originFromHost(api.host),
|
|
270
|
+
headers: api.jwt ? {
|
|
271
|
+
Authorization: `Bearer ${api.jwt}`
|
|
272
|
+
} : undefined,
|
|
273
|
+
maxBytes: CONSTANTS.CC_FILE_MAX_BYTES
|
|
274
|
+
},
|
|
275
|
+
onCaptionUploaded: subtitle => {
|
|
276
|
+
// Update local state so "Done" button knows about it
|
|
277
|
+
setSubtitles(prev => [...prev.filter(s => s.locale !== subtitle.locale), subtitle]);
|
|
278
|
+
onCaptionsModified?.();
|
|
279
|
+
},
|
|
280
|
+
onCaptionDeleted: locale => {
|
|
281
|
+
setSubtitles(prev => prev.filter(s => s.locale !== locale));
|
|
282
|
+
onCaptionsModified?.();
|
|
283
|
+
},
|
|
284
|
+
onDirtyStateChanged: handleDirtyCheck
|
|
285
|
+
}))), isAsrCaptioningImprovements ? /*#__PURE__*/React.createElement(Flex.Item, {
|
|
286
|
+
padding: "small"
|
|
287
|
+
}, /*#__PURE__*/React.createElement(Link, {
|
|
288
|
+
id: "tray-transcript-help-link",
|
|
289
|
+
variant: "standalone",
|
|
290
|
+
renderIcon: /*#__PURE__*/React.createElement(IconExternalLinkLine, null),
|
|
291
|
+
href: "https://productmarketing.instructuremedia.com/embed/32388c5a-580c-40f0-85a2-6b4042ddcccb",
|
|
292
|
+
target: "_blank",
|
|
293
|
+
rel: "noopener noreferrer"
|
|
294
|
+
}, formatMessage('How to request and edit captions?'))) : null)), /*#__PURE__*/React.createElement(Flex.Item, {
|
|
117
295
|
background: "secondary",
|
|
118
296
|
borderWidth: "small none none none",
|
|
119
297
|
padding: "small medium",
|
|
120
298
|
textAlign: "end"
|
|
299
|
+
}, /*#__PURE__*/React.createElement(Tooltip, {
|
|
300
|
+
renderTip: formatMessage('Unsaved changes will be lost.'),
|
|
301
|
+
placement: "top",
|
|
302
|
+
on: ['hover', 'focus'],
|
|
303
|
+
preventTooltip: !hasUnsavedChanges,
|
|
304
|
+
mountNode: instuiPopupMountNodeFn
|
|
121
305
|
}, /*#__PURE__*/React.createElement(Button, {
|
|
122
306
|
onClick: e => handleSave(e, contentProps),
|
|
123
|
-
color: "primary"
|
|
124
|
-
|
|
307
|
+
color: "primary",
|
|
308
|
+
interaction: saveDisabled ? 'disabled' : 'enabled'
|
|
309
|
+
}, formatMessage('Done')))))))));
|
|
125
310
|
}
|
|
126
311
|
AudioOptionsTray.propTypes = {
|
|
127
312
|
onEntered: func,
|
|
@@ -139,13 +324,20 @@ AudioOptionsTray.propTypes = {
|
|
|
139
324
|
titleText: string.isRequired,
|
|
140
325
|
tracks: arrayOf(shape({
|
|
141
326
|
locale: string.isRequired
|
|
142
|
-
}))
|
|
143
|
-
|
|
327
|
+
})),
|
|
328
|
+
viewerRestrictions: shape({
|
|
329
|
+
show_rolling_transcript: bool
|
|
330
|
+
})
|
|
331
|
+
}).isRequired,
|
|
332
|
+
onCaptionsModified: func,
|
|
333
|
+
isLoading: bool,
|
|
334
|
+
id: string
|
|
144
335
|
};
|
|
145
336
|
AudioOptionsTray.defaultProps = {
|
|
146
337
|
onEntered: null,
|
|
147
338
|
onExited: null,
|
|
148
339
|
onDismiss: null,
|
|
149
340
|
onSave: null,
|
|
150
|
-
requestSubtitlesFromIframe: () => {}
|
|
341
|
+
requestSubtitlesFromIframe: () => {},
|
|
342
|
+
onCaptionsModified: null
|
|
151
343
|
};
|
|
@@ -16,14 +16,16 @@
|
|
|
16
16
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import
|
|
20
|
-
import { func, oneOf, shape, string } from 'prop-types';
|
|
21
|
-
import { contentTrayDocumentShape } from '../../shared/fileShape';
|
|
22
|
-
import formatMessage from '../../../../format-message';
|
|
19
|
+
import { trackPendoEvent } from '@instructure/canvas-media';
|
|
23
20
|
import { Text } from '@instructure/ui-text';
|
|
24
21
|
import { View } from '@instructure/ui-view';
|
|
22
|
+
import { func, oneOf, shape, string } from 'prop-types';
|
|
23
|
+
import React, { useRef } from 'react';
|
|
24
|
+
import { LoadingIndicator, LoadingStatus, LoadMoreButton, useIncrementalLoading } from '../../../../common/incremental-loading';
|
|
25
|
+
import formatMessage from '../../../../format-message';
|
|
26
|
+
import RCEGlobals from '../../../RCEGlobals';
|
|
25
27
|
import Link from '../../instructure_documents/components/Link';
|
|
26
|
-
import {
|
|
28
|
+
import { contentTrayDocumentShape } from '../../shared/fileShape';
|
|
27
29
|
const PENDING_MEDIA_ENTRY_ID = 'maybe';
|
|
28
30
|
function hasFiles(media) {
|
|
29
31
|
return media.files.length > 0;
|
|
@@ -84,6 +86,15 @@ export default function MediaPanel(props) {
|
|
|
84
86
|
searchString
|
|
85
87
|
});
|
|
86
88
|
const handleFileClick = file => {
|
|
89
|
+
if (RCEGlobals.getFeatures()?.rce_asr_captioning_improvements) {
|
|
90
|
+
const contentType = file.content_type || file['content-type'] || '';
|
|
91
|
+
trackPendoEvent('canvas_native_media_embedded', {
|
|
92
|
+
insertion_method: 'select_existing',
|
|
93
|
+
media_id: file.id,
|
|
94
|
+
media_kind: contentType.startsWith('audio/') ? 'audio' : 'video',
|
|
95
|
+
resourceType: props.contextType
|
|
96
|
+
});
|
|
97
|
+
}
|
|
87
98
|
props.onMediaEmbed(file);
|
|
88
99
|
};
|
|
89
100
|
return /*#__PURE__*/React.createElement(View, {
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
export const CONTAINER_ID: "instructure-video-options-tray-container";
|
|
2
|
-
export namespace
|
|
2
|
+
export namespace STUDIO_PLAYER_VIDEO_SIZE_DEFAULT {
|
|
3
3
|
let height: string;
|
|
4
4
|
let width: string;
|
|
5
5
|
}
|
|
6
|
-
export namespace
|
|
7
|
-
let height_1: string;
|
|
8
|
-
export { height_1 as height };
|
|
6
|
+
export namespace AUDIO_PLAYER_SIZE {
|
|
9
7
|
let width_1: string;
|
|
10
8
|
export { width_1 as width };
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
let width_2: string;
|
|
14
|
-
export { width_2 as width };
|
|
15
|
-
let height_2: string;
|
|
16
|
-
export { height_2 as height };
|
|
9
|
+
let height_1: string;
|
|
10
|
+
export { height_1 as height };
|
|
17
11
|
}
|
|
18
12
|
export function videoDefaultSize(): {
|
|
19
13
|
height: string;
|
|
@@ -24,14 +18,21 @@ export default class TrayController {
|
|
|
24
18
|
_isOpen: boolean;
|
|
25
19
|
_shouldOpen: boolean;
|
|
26
20
|
_renderId: number;
|
|
21
|
+
_skipFocusOnExit: boolean;
|
|
22
|
+
_captionsModified: boolean;
|
|
23
|
+
requestSubtitlesFromIframe(cb: any): void;
|
|
24
|
+
isStudioVideo: boolean;
|
|
27
25
|
get $container(): HTMLElement;
|
|
28
26
|
get isOpen(): boolean;
|
|
29
27
|
showTrayForEditor(editor: any): void;
|
|
30
28
|
$videoContainer: Element | null | undefined;
|
|
31
|
-
|
|
29
|
+
_isPlayerReady: boolean | undefined;
|
|
30
|
+
hideTrayForEditor(editor: any, skipFocusOnExit?: boolean): void;
|
|
32
31
|
_applyVideoOptions(videoOptions: any): void;
|
|
32
|
+
_listenForPlayerIframeToLoad(currentMediaId: any): void;
|
|
33
|
+
_iframeLoadingListener: AbortController | undefined;
|
|
34
|
+
_reloadVideoPlayer(): void;
|
|
33
35
|
_dismissTray(): void;
|
|
34
|
-
requestSubtitlesFromIframe(cb: any): void;
|
|
35
36
|
_subtitleListener: AbortController | undefined;
|
|
36
|
-
_renderTray(
|
|
37
|
+
_renderTray(): void;
|
|
37
38
|
}
|