diff --git a/src/editors/AdvancedEditor.test.tsx b/src/editors/AdvancedEditor.test.tsx
new file mode 100644
index 0000000000..32ab90945e
--- /dev/null
+++ b/src/editors/AdvancedEditor.test.tsx
@@ -0,0 +1,62 @@
+import { getConfig } from '@edx/frontend-platform';
+
+import {
+ render,
+ initializeMocks,
+} from '../testUtils';
+import AdvancedEditor from './AdvancedEditor';
+
+jest.mock('./containers/EditorContainer', () => ({
+ EditorModalWrapper: jest.fn(() => (
Advanced Editor Iframe
)),
+}));
+
+describe('AdvancedEditor', () => {
+ beforeEach(() => {
+ initializeMocks();
+ });
+
+ it('should call onClose when receiving "cancel-clicked" message', () => {
+ const onCloseMock = jest.fn();
+
+ render();
+
+ const messageEvent = new MessageEvent('message', {
+ data: 'cancel-clicked',
+ origin: getConfig().STUDIO_BASE_URL,
+ });
+
+ window.dispatchEvent(messageEvent);
+
+ expect(onCloseMock).toHaveBeenCalled();
+ });
+
+ it('should call onClose when receiving "save-clicked" message', () => {
+ const onCloseMock = jest.fn();
+
+ render();
+
+ const messageEvent = new MessageEvent('message', {
+ data: 'save-clicked',
+ origin: getConfig().STUDIO_BASE_URL,
+ });
+
+ window.dispatchEvent(messageEvent);
+
+ expect(onCloseMock).toHaveBeenCalled();
+ });
+
+ it('should not call onClose if the message is from an invalid origin', () => {
+ const onCloseMock = jest.fn();
+
+ render();
+
+ const messageEvent = new MessageEvent('message', {
+ data: 'cancel-clicked',
+ origin: 'https://invalid-origin.com',
+ });
+
+ window.dispatchEvent(messageEvent);
+
+ expect(onCloseMock).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/editors/AdvancedEditor.tsx b/src/editors/AdvancedEditor.tsx
new file mode 100644
index 0000000000..a044e6ad9d
--- /dev/null
+++ b/src/editors/AdvancedEditor.tsx
@@ -0,0 +1,41 @@
+import { useEffect } from 'react';
+import { getConfig } from '@edx/frontend-platform';
+
+import { LibraryBlock } from '../library-authoring/LibraryBlock';
+import { EditorModalWrapper } from './containers/EditorContainer';
+
+interface AdvancedEditorProps {
+ usageKey: string,
+ onClose: Function | null,
+}
+
+const AdvancedEditor = ({ usageKey, onClose }: AdvancedEditorProps) => {
+ useEffect(() => {
+ const handleIframeMessage = (event) => {
+ if (event.origin !== getConfig().STUDIO_BASE_URL) {
+ return;
+ }
+
+ if (onClose && (event.data === 'cancel-clicked' || event.data === 'save-clicked')) {
+ onClose();
+ }
+ };
+
+ window.addEventListener('message', handleIframeMessage);
+
+ return () => {
+ window.removeEventListener('message', handleIframeMessage);
+ };
+ }, []);
+
+ return (
+ void}>
+
+
+ );
+};
+
+export default AdvancedEditor;
diff --git a/src/editors/Editor.tsx b/src/editors/Editor.tsx
index 8e52448242..33f24c9f39 100644
--- a/src/editors/Editor.tsx
+++ b/src/editors/Editor.tsx
@@ -2,14 +2,13 @@
// as its parent, so they are tested together in EditorPage.test.tsx
import React from 'react';
import { useDispatch } from 'react-redux';
-import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import messages from './messages';
import * as hooks from './hooks';
import supportedEditors from './supportedEditors';
import type { EditorComponent } from './EditorComponent';
import { useEditorContext } from './EditorContext';
+import AdvancedEditor from './AdvancedEditor';
export interface Props extends EditorComponent {
blockType: string;
@@ -43,9 +42,17 @@ const Editor: React.FC = ({
const { fullScreen } = useEditorContext();
const EditorComponent = supportedEditors[blockType];
- const innerEditor = (EditorComponent !== undefined)
- ?
- : ;
+
+ if (EditorComponent === undefined && blockId) {
+ return (
+
+ );
+ }
+
+ const innerEditor = ;
if (fullScreen) {
return (
diff --git a/src/editors/EditorPage.test.tsx b/src/editors/EditorPage.test.tsx
index 4ae9817d3b..66d7ffac95 100644
--- a/src/editors/EditorPage.test.tsx
+++ b/src/editors/EditorPage.test.tsx
@@ -26,6 +26,9 @@ jest.spyOn(editorCmsApi, 'fetchByUnitId').mockImplementation(async () => ({
}],
},
}));
+jest.mock('../library-authoring/LibraryBlock', () => ({
+ LibraryBlock: jest.fn(() => (Advanced Editor Iframe
)),
+}));
const defaultPropsHtml = {
blockId: 'block-v1:Org+TS100+24+type@html+block@123456html',
@@ -79,9 +82,7 @@ describe('EditorPage', () => {
expect(modalElement.classList).not.toContain('pgn__modal-xl');
});
- test('it shows an error message if there is no corresponding editor', async () => {
- // We can edit 'html', 'problem', and 'video' blocks.
- // But if we try to edit some other type, say 'fake', we should get an error:
+ test('it shows the Advanced Editor if there is no corresponding editor', async () => {
jest.spyOn(editorCmsApi, 'fetchBlockById').mockImplementationOnce(async () => ( // eslint-disable-next-line
{ status: 200, data: { display_name: 'Fake Un-editable Block', category: 'fake', metadata: {}, data: '' } }
));
@@ -93,6 +94,6 @@ describe('EditorPage', () => {
};
render();
- expect(await screen.findByText('Error: Could Not find Editor')).toBeInTheDocument();
+ expect(await screen.findByText('Advanced Editor Iframe')).toBeInTheDocument();
});
});
diff --git a/src/editors/messages.ts b/src/editors/messages.ts
index 4b1134a270..1ac257514e 100644
--- a/src/editors/messages.ts
+++ b/src/editors/messages.ts
@@ -2,11 +2,6 @@ import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
- couldNotFindEditor: {
- id: 'authoring.editorpage.selecteditor.error',
- defaultMessage: 'Error: Could Not find Editor',
- description: 'Error Message Dispayed When An unsopported Editor is desired in V2',
- },
dropVideoFileHere: {
defaultMessage: 'Drag and drop video here or click to upload',
id: 'VideoUploadEditor.dropVideoFileHere',
diff --git a/src/library-authoring/LibraryBlock/LibraryBlock.tsx b/src/library-authoring/LibraryBlock/LibraryBlock.tsx
index 4397090edd..e635f1f8ba 100644
--- a/src/library-authoring/LibraryBlock/LibraryBlock.tsx
+++ b/src/library-authoring/LibraryBlock/LibraryBlock.tsx
@@ -10,6 +10,7 @@ interface LibraryBlockProps {
onBlockNotification?: (event: { eventType: string; [key: string]: any }) => void;
usageKey: string;
version?: VersionSpec;
+ view?: string;
}
/**
* React component that displays an XBlock in a sandboxed IFrame.
@@ -20,7 +21,12 @@ interface LibraryBlockProps {
* cannot access things like the user's cookies, nor can it make GET/POST
* requests as the user. However, it is allowed to call any XBlock handlers.
*/
-export const LibraryBlock = ({ onBlockNotification, usageKey, version }: LibraryBlockProps) => {
+export const LibraryBlock = ({
+ onBlockNotification,
+ usageKey,
+ version,
+ view,
+}: LibraryBlockProps) => {
const iframeRef = useRef(null);
const [iFrameHeight, setIFrameHeight] = useState(50);
const studioBaseUrl = getConfig().STUDIO_BASE_URL;
@@ -71,6 +77,8 @@ export const LibraryBlock = ({ onBlockNotification, usageKey, version }: Library
const queryStr = version ? `?version=${version}` : '';
+ const xblockView = view ?? 'student_view';
+
return (
> = () => {