feat: tinyMCE config changes (#253)

This commit is contained in:
Raymond Zhou
2023-02-27 10:48:04 -08:00
committed by GitHub
parent 3c3361c765
commit e0c5573c8d
8 changed files with 71 additions and 42 deletions

View File

@@ -16,6 +16,7 @@ exports[`QuestionWidget render snapshot: renders correct default 1`] = `
<Editor
problemEditorConfig={
Object {
"isLibrary": false,
"question": "This is my question",
"setEditorRef": [MockFunction hooks.prepareEditorRef.setEditorRef],
"updateQuestion": [MockFunction],

View File

@@ -25,8 +25,9 @@ import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/image';
import 'tinymce/plugins/imagetools';
// This widget should be connected, grab all questions from store, update them as needed.
export const QuestionWidget = ({
// redux
isLibrary,
question,
updateQuestion,
}) => {
@@ -39,6 +40,7 @@ export const QuestionWidget = ({
</div>
<Editor {
...hooks.problemEditorConfig({
isLibrary,
setEditorRef,
question,
updateQuestion,
@@ -49,12 +51,18 @@ export const QuestionWidget = ({
);
};
QuestionWidget.defaultProps = {
isLibrary: null,
};
QuestionWidget.propTypes = {
// redux
isLibrary: PropTypes.bool,
question: PropTypes.string.isRequired,
updateQuestion: PropTypes.func.isRequired,
};
export const mapStateToProps = (state) => ({
isLibrary: selectors.app.isLibrary(state),
question: selectors.problem.question(state),
});

View File

@@ -11,6 +11,9 @@ jest.mock('../../../../../data/redux', () => ({
},
},
selectors: {
app: {
isLibrary: jest.fn(state => ({ isLibrary: state })),
},
problem: {
question: jest.fn(state => ({ question: state })),
},
@@ -38,6 +41,7 @@ jest.mock('../../../hooks', () => ({
describe('QuestionWidget', () => {
const props = {
isLibrary: false,
question: 'This is my question',
updateQuestion: jest.fn(),
};
@@ -48,6 +52,9 @@ describe('QuestionWidget', () => {
});
describe('mapStateToProps', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
test('isLibrary from app.isLibrary', () => {
expect(mapStateToProps(testState).isLibrary).toEqual(selectors.app.isLibrary(testState));
});
test('question from problem.question', () => {
expect(mapStateToProps(testState).question).toEqual(selectors.problem.question(testState));
});

View File

@@ -1,9 +1,8 @@
import {
useRef, useCallback, useState, useEffect,
} from 'react';
import tinyMCEStyles from '../../data/constants/tinyMCEStyles';
import { StrictDict } from '../../utils';
import pluginConfig from '../TextEditor/pluginConfig';
import tinyMCEConfig from '../../data/constants/tinyMCEConfig';
import * as module from './hooks';
export const state = StrictDict({
@@ -63,6 +62,7 @@ export const setupCustomBehavior = ({ updateQuestion }) => (editor) => {
};
export const problemEditorConfig = ({
isLibrary,
setEditorRef,
question,
updateQuestion,
@@ -72,17 +72,12 @@ export const problemEditorConfig = ({
},
initialValue: question || '',
init: {
skin: false,
content_css: false,
content_style: tinyMCEStyles,
menubar: false,
branding: false,
min_height: 150,
placeholder: 'Enter your question',
...tinyMCEConfig(isLibrary).config.shared,
...tinyMCEConfig(isLibrary).config.problemEditor,
formats: { label: { inline: 'label' } },
setup: module.setupCustomBehavior({ updateQuestion }),
toolbar: `${pluginConfig().toolbar} | customLabelButton`,
plugins: 'autoresize',
setup: module.setupCustomBehavior({ updateQuestion }),
toolbar: `${tinyMCEConfig().toolbar} | customLabelButton`,
},
});

View File

@@ -3,7 +3,7 @@ import { MockUseState } from '../../../testUtils';
// import tinyMCE from '../../data/constants/tinyMCE';
import { keyStore } from '../../utils';
import pluginConfig from '../TextEditor/pluginConfig';
import tinyMCEConfig from '../../data/constants/tinyMCEConfig';
import * as module from './hooks';
jest.mock('react', () => ({
@@ -104,7 +104,13 @@ describe('Problem editor hooks', () => {
});
test('It configures plugins and toolbars correctly', () => {
expect(output.init.plugins).toEqual('autoresize');
expect(output.init.toolbar).toEqual(`${pluginConfig().toolbar} | customLabelButton`);
expect(output.init.toolbar).toEqual(`${tinyMCEConfig().toolbar} | customLabelButton`);
Object.keys(tinyMCEConfig(props.isLibrary).config.shared).forEach(key => {
expect(output.init[key]).toEqual(tinyMCEConfig(props.isLibrary).config.shared[key]);
});
Object.keys(tinyMCEConfig(props.isLibrary).config.problemEditor).forEach(key => {
expect(output.init[key]).toEqual(tinyMCEConfig(props.isLibrary).config.problemEditor[key]);
});
});
it('calls setupCustomBehavior on setup', () => {

View File

@@ -4,8 +4,7 @@ import {
import { StrictDict } from '../../utils';
import tinyMCE from '../../data/constants/tinyMCE';
import tinyMCEStyles from '../../data/constants/tinyMCEStyles';
import pluginConfig from './pluginConfig';
import tinyMCEConfig from '../../data/constants/tinyMCEConfig';
import * as appHooks from '../../hooks';
import * as module from './hooks';
@@ -110,24 +109,20 @@ export const editorConfig = ({
},
initialValue: blockValue ? blockValue.data.data : '',
init: {
...pluginConfig(isLibrary).config,
skin: false,
content_css: false,
content_style: tinyMCEStyles,
...tinyMCEConfig(isLibrary).config.shared,
...tinyMCEConfig(isLibrary).config.textEditor,
contextmenu: 'link table',
document_base_url: lmsEndpointUrl,
init_instance_callback: module.checkRelativeUrl(module.fetchImageUrls(images)),
imagetools_cors_hosts: [removeProtocolFromUrl(lmsEndpointUrl), removeProtocolFromUrl(studioEndpointUrl)],
imagetools_toolbar: pluginConfig(isLibrary).imageToolbar,
plugins: pluginConfig(isLibrary).plugins,
imagetools_toolbar: tinyMCEConfig(isLibrary).imageToolbar,
plugins: tinyMCEConfig(isLibrary).plugins,
setup: module.setupCustomBehavior({
openImgModal,
openSourceCodeModal,
setImage: setSelection,
}),
toolbar: pluginConfig(isLibrary).toolbar,
valid_children: '+body[style]',
valid_elements: '*[*]',
toolbar: tinyMCEConfig(isLibrary).toolbar,
},
});

View File

@@ -4,7 +4,7 @@ import { MockUseState } from '../../../testUtils';
import tinyMCE from '../../data/constants/tinyMCE';
import { keyStore } from '../../utils';
import * as appHooks from '../../hooks';
import pluginConfig from './pluginConfig';
import tinyMCEConfig from '../../data/constants/tinyMCEConfig';
import * as module from './hooks';
jest.mock('react', () => ({
@@ -150,11 +150,14 @@ describe('TextEditor hooks', () => {
expect(output.initialValue).toBe(htmltext);
});
test('It configures plugins and toolbars correctly', () => {
expect(output.init.plugins).toEqual(pluginConfig(props.isLibrary).plugins);
expect(output.init.imagetools_toolbar).toEqual(pluginConfig(props.isLibrary).imageToolbar);
expect(output.init.toolbar).toEqual(pluginConfig(props.isLibrary).toolbar);
Object.keys(pluginConfig(props.isLibrary).config).forEach(key => {
expect(output.init[key]).toEqual(pluginConfig(props.isLibrary).config[key]);
expect(output.init.plugins).toEqual(tinyMCEConfig(props.isLibrary).plugins);
expect(output.init.imagetools_toolbar).toEqual(tinyMCEConfig(props.isLibrary).imageToolbar);
expect(output.init.toolbar).toEqual(tinyMCEConfig(props.isLibrary).toolbar);
Object.keys(tinyMCEConfig(props.isLibrary).config.shared).forEach(key => {
expect(output.init[key]).toEqual(tinyMCEConfig(props.isLibrary).config.shared[key]);
});
Object.keys(tinyMCEConfig(props.isLibrary).config.textEditor).forEach(key => {
expect(output.init[key]).toEqual(tinyMCEConfig(props.isLibrary).config.textEditor[key]);
});
// Commented out as we investigate whether this is only needed for image proxy
// expect(output.init.imagetools_cors_hosts).toMatchObject([props.lmsEndpointUrl]);

View File

@@ -1,9 +1,10 @@
import { StrictDict } from '../../utils';
import { buttons, plugins } from '../../data/constants/tinyMCE';
import { buttons, plugins } from './tinyMCE';
import tinyMCEStyles from './tinyMCEStyles';
const mapToolbars = toolbars => toolbars.map(toolbar => toolbar.join(' ')).join(' | ');
const pluginConfig = (isLibrary) => {
const tinyMCEConfig = (isLibrary) => {
const image = isLibrary ? '' : plugins.image;
const imageTools = isLibrary ? '' : plugins.imagetools;
const imageUploadButton = isLibrary ? '' : buttons.imageUploadButton;
@@ -51,17 +52,30 @@ const pluginConfig = (isLibrary) => {
[editImageSettings],
]),
config: {
branding: false,
height: '100%',
menubar: false,
min_height: 500,
toolbar_sticky: true,
toolbar_sticky_offset: 76,
relative_urls: true,
convert_urls: false,
shared: {
branding: false,
content_css: false,
content_style: tinyMCEStyles,
menubar: false,
skin: false,
valid_children: '+body[style]',
valid_elements: '*[*]',
},
textEditor: {
height: '100%',
min_height: 500,
toolbar_sticky: true,
toolbar_sticky_offset: 76,
relative_urls: true,
convert_urls: false,
},
problemEditor: {
min_height: 150,
placeholder: 'Enter your question',
},
},
})
);
};
export default pluginConfig;
export default tinyMCEConfig;