feat: refactor tinymce editor to sharedComponents (#255)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SourceCodeModal renders as expected with default behavior 1`] = `
|
||||
<BaseModal
|
||||
close={[MockFunction]}
|
||||
confirmAction={
|
||||
<Button
|
||||
0="S"
|
||||
1="o"
|
||||
2="M"
|
||||
3="e"
|
||||
4="v"
|
||||
5="A"
|
||||
6="l"
|
||||
7="u"
|
||||
8="e"
|
||||
variant="primary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Save"
|
||||
description="Label for Save button for the source code editor"
|
||||
id="authoring.texteditor.sourcecodemodal.next.label"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
isOpen={false}
|
||||
size="xl"
|
||||
title="Edit Source Code"
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"height": "300px",
|
||||
"padding": "10px 30px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
innerRef="moCKrEf"
|
||||
value="mOckHtMl"
|
||||
/>
|
||||
</div>
|
||||
</BaseModal>
|
||||
`;
|
||||
27
src/editors/sharedComponents/SourceCodeModal/hooks.js
Normal file
27
src/editors/sharedComponents/SourceCodeModal/hooks.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { useRef } from 'react';
|
||||
import * as module from './hooks';
|
||||
|
||||
export const getSaveBtnProps = ({ editorRef, ref, close }) => ({
|
||||
onClick: () => {
|
||||
if (editorRef && editorRef.current && ref && ref.current) {
|
||||
const content = ref.current.state.doc.toString();
|
||||
editorRef.current.setContent(content);
|
||||
close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const prepareSourceCodeModal = ({ editorRef, close }) => {
|
||||
const ref = useRef();
|
||||
const saveBtnProps = module.getSaveBtnProps({ editorRef, ref, close });
|
||||
|
||||
if (editorRef && editorRef.current && typeof editorRef.current.getContent === 'function') {
|
||||
const value = editorRef?.current?.getContent();
|
||||
return { saveBtnProps, value, ref };
|
||||
}
|
||||
return { saveBtnProps, value: null, ref };
|
||||
};
|
||||
|
||||
export default {
|
||||
prepareSourceCodeModal,
|
||||
};
|
||||
60
src/editors/sharedComponents/SourceCodeModal/hooks.test.js
Normal file
60
src/editors/sharedComponents/SourceCodeModal/hooks.test.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
|
||||
import * as module from './hooks';
|
||||
|
||||
jest.mock('react', () => ({
|
||||
...jest.requireActual('react'),
|
||||
useRef: jest.fn(val => ({ current: val })),
|
||||
useEffect: jest.fn(),
|
||||
useCallback: (cb, prereqs) => ({ cb, prereqs }),
|
||||
}));
|
||||
|
||||
describe('SourceCodeModal hooks', () => {
|
||||
const mockContent = 'sOmEMockHtML';
|
||||
const mockSetContent = jest.fn();
|
||||
const mockEditorRef = {
|
||||
current:
|
||||
{
|
||||
setContent: mockSetContent,
|
||||
getContent: jest.fn(() => mockContent),
|
||||
},
|
||||
};
|
||||
const mockClose = jest.fn();
|
||||
test('getSaveBtnProps', () => {
|
||||
const mockRef = {
|
||||
current: {
|
||||
state: {
|
||||
doc: mockContent,
|
||||
},
|
||||
},
|
||||
};
|
||||
const input = {
|
||||
ref: mockRef,
|
||||
editorRef: mockEditorRef,
|
||||
close: mockClose,
|
||||
};
|
||||
const resultProps = module.getSaveBtnProps(input);
|
||||
resultProps.onClick();
|
||||
expect(mockSetContent).toHaveBeenCalledWith(mockContent);
|
||||
expect(mockClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('prepareSourceCodeModal', () => {
|
||||
const props = {
|
||||
close: mockClose,
|
||||
editorRef: mockEditorRef,
|
||||
};
|
||||
const mockRef = { current: 'rEf' };
|
||||
const spyRef = jest.spyOn(React, 'useRef').mockReturnValueOnce(mockRef);
|
||||
const mockButton = 'mOcKBuTton';
|
||||
|
||||
const spyButtons = jest.spyOn(module, 'getSaveBtnProps').mockImplementation(
|
||||
() => mockButton,
|
||||
);
|
||||
|
||||
const result = module.prepareSourceCodeModal(props);
|
||||
expect(spyRef).toHaveBeenCalled();
|
||||
expect(spyButtons).toHaveBeenCalled();
|
||||
expect(result).toStrictEqual({ saveBtnProps: mockButton, value: mockEditorRef.current.getContent(), ref: mockRef });
|
||||
});
|
||||
});
|
||||
59
src/editors/sharedComponents/SourceCodeModal/index.jsx
Normal file
59
src/editors/sharedComponents/SourceCodeModal/index.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
intlShape,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import messages from './messages';
|
||||
import hooks from './hooks';
|
||||
import BaseModal from '../BaseModal';
|
||||
|
||||
import CodeEditor from '../CodeEditor';
|
||||
|
||||
export const SourceCodeModal = ({
|
||||
isOpen,
|
||||
close,
|
||||
editorRef,
|
||||
// injected
|
||||
intl,
|
||||
}) => {
|
||||
const { saveBtnProps, value, ref } = hooks.prepareSourceCodeModal({ editorRef, close });
|
||||
return (
|
||||
<BaseModal
|
||||
close={close}
|
||||
size="xl"
|
||||
confirmAction={(
|
||||
<Button {...saveBtnProps} variant="primary">
|
||||
<FormattedMessage {...messages.saveButtonLabel} />
|
||||
</Button>
|
||||
)}
|
||||
isOpen={isOpen}
|
||||
title={intl.formatMessage(messages.titleLabel)}
|
||||
>
|
||||
<div style={{ padding: '10px 30px', height: '300px' }}>
|
||||
<CodeEditor
|
||||
innerRef={ref}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</BaseModal>
|
||||
);
|
||||
};
|
||||
|
||||
SourceCodeModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
editorRef: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.shape({ current: PropTypes.any }),
|
||||
]).isRequired,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(SourceCodeModal);
|
||||
36
src/editors/sharedComponents/SourceCodeModal/index.test.jsx
Normal file
36
src/editors/sharedComponents/SourceCodeModal/index.test.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import hooks from './hooks';
|
||||
import { formatMessage } from '../../../testUtils';
|
||||
|
||||
import { SourceCodeModal } from '.';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
prepareSourceCodeModal: jest.fn(() => {
|
||||
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('SourceCodeModal', () => {
|
||||
const mockClose = jest.fn();
|
||||
|
||||
const props = {
|
||||
isOpen: false,
|
||||
close: mockClose,
|
||||
editorRef: {
|
||||
current: jest.fn(),
|
||||
},
|
||||
intl: { formatMessage },
|
||||
};
|
||||
test('renders as expected with default behavior', () => {
|
||||
const mocksaveBtnProps = 'SoMevAlue';
|
||||
const mockvalue = 'mOckHtMl';
|
||||
const mockref = 'moCKrEf';
|
||||
hooks.prepareSourceCodeModal.mockReturnValueOnce({
|
||||
saveBtnProps: mocksaveBtnProps,
|
||||
value: mockvalue,
|
||||
ref: mockref,
|
||||
});
|
||||
expect(shallow(<SourceCodeModal {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
13
src/editors/sharedComponents/SourceCodeModal/messages.js
Normal file
13
src/editors/sharedComponents/SourceCodeModal/messages.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export const messages = {
|
||||
saveButtonLabel: {
|
||||
id: 'authoring.texteditor.sourcecodemodal.next.label',
|
||||
defaultMessage: 'Save',
|
||||
description: 'Label for Save button for the source code editor',
|
||||
},
|
||||
titleLabel: {
|
||||
id: 'authoring.texteditor.sourcecodemodal.title.label',
|
||||
defaultMessage: 'Edit Source Code',
|
||||
description: 'Title for the source code editor',
|
||||
},
|
||||
};
|
||||
export default messages;
|
||||
Reference in New Issue
Block a user