feat: remove the ability to use image tools for content libraries

This commit is contained in:
Kristin Aoki
2022-08-30 16:40:17 -04:00
committed by GitHub
parent 36380edce4
commit 4e69fffbef
8 changed files with 196 additions and 66 deletions

View File

@@ -1,5 +1,74 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TextEditor snapshots ImageUploadModal is not rendered 1`] = `
<EditorContainer
getContent={
Object {
"getContent": Object {
"editorRef": Object {
"current": Object {
"value": "something",
},
},
"isRaw": false,
},
}
}
onClose={[MockFunction props.onClose]}
>
<div
className="editor-body h-75 overflow-auto"
>
<SourceCodeModal
close={[MockFunction modal.closeModal]}
editorRef={
Object {
"current": Object {
"value": "something",
},
}
}
isOpen={false}
/>
<Toast
onClose={[MockFunction hooks.nullMethod]}
show={false}
>
<FormattedMessage
defaultMessage="Error: Could Not Load Text Content"
description="Error Message Dispayed When HTML content fails to Load"
id="authoring.texteditor.load.error"
/>
</Toast>
<Editor
editorConfig={
Object {
"blockValue": Object {
"data": Object {
"some": "eDiTablE Text",
},
},
"clearSelection": [MockFunction hooks.selectedImage.clearSelection],
"images": Object {
"sOmEuiMAge": Object {
"staTICUrl": "/assets/sOmEuiMAge",
},
},
"initializeEditor": [MockFunction args.intializeEditor],
"isLibrary": true,
"lmsEndpointUrl": "sOmEvaLue.cOm",
"openImgModal": [MockFunction modal.openModal],
"openSourceCodeModal": [MockFunction modal.openModal],
"setEditorRef": [MockFunction hooks.prepareEditorRef.setEditorRef],
"setSelection": [MockFunction hooks.selectedImage.setSelection],
"studioEndpointUrl": "sOmEoThERvaLue.cOm",
}
}
/>
</div>
</EditorContainer>
`;
exports[`TextEditor snapshots block failed to load, Toast is shown 1`] = `
<EditorContainer
getContent={
@@ -76,6 +145,7 @@ exports[`TextEditor snapshots block failed to load, Toast is shown 1`] = `
},
},
"initializeEditor": [MockFunction args.intializeEditor],
"isLibrary": false,
"lmsEndpointUrl": "sOmEvaLue.cOm",
"openImgModal": [MockFunction modal.openModal],
"openSourceCodeModal": [MockFunction modal.openModal],
@@ -313,6 +383,7 @@ exports[`TextEditor snapshots renders as expected with default behavior 1`] = `
},
},
"initializeEditor": [MockFunction args.intializeEditor],
"isLibrary": false,
"lmsEndpointUrl": "sOmEvaLue.cOm",
"openImgModal": [MockFunction modal.openModal],
"openSourceCodeModal": [MockFunction modal.openModal],

View File

@@ -100,6 +100,7 @@ export const editorConfig = ({
setSelection,
studioEndpointUrl,
images,
isLibrary,
}) => ({
onInit: (evt, editor) => {
setEditorRef(editor);
@@ -107,7 +108,7 @@ export const editorConfig = ({
},
initialValue: blockValue ? blockValue.data.data : '',
init: {
...pluginConfig.config,
...pluginConfig(isLibrary).config,
skin: false,
content_css: false,
content_style: tinyMCEStyles,
@@ -115,14 +116,14 @@ export const editorConfig = ({
document_base_url: lmsEndpointUrl,
init_instance_callback: module.checkRelativeUrl(module.fetchImageUrls(images)),
imagetools_cors_hosts: [removeProtocolFromUrl(lmsEndpointUrl), removeProtocolFromUrl(studioEndpointUrl)],
imagetools_toolbar: pluginConfig.imageToolbar,
plugins: pluginConfig.plugins,
imagetools_toolbar: pluginConfig(isLibrary).imageToolbar,
plugins: pluginConfig(isLibrary).plugins,
setup: module.setupCustomBehavior({
openImgModal,
openSourceCodeModal,
setImage: setSelection,
}),
toolbar: pluginConfig.toolbar,
toolbar: pluginConfig(isLibrary).toolbar,
valid_children: '+body[style]',
valid_elements: '*[*]',
},

View File

@@ -107,6 +107,7 @@ describe('TextEditor hooks', () => {
lmsEndpointUrl: 'sOmEuRl.cOm',
studioEndpointUrl: 'sOmEoThEruRl.cOm',
images: { sOmEuiMAge: { staTICUrl: '/assets/sOmEuiMAge' } },
isLibrary: false,
};
const evt = 'fakeEvent';
const editor = 'myEditor';
@@ -135,11 +136,11 @@ describe('TextEditor hooks', () => {
expect(output.initialValue).toBe(htmltext);
});
test('It configures plugins and toolbars correctly', () => {
expect(output.init.plugins).toEqual(pluginConfig.plugins);
expect(output.init.imagetools_toolbar).toEqual(pluginConfig.imageToolbar);
expect(output.init.toolbar).toEqual(pluginConfig.toolbar);
Object.keys(pluginConfig.config).forEach(key => {
expect(output.init[key]).toEqual(pluginConfig.config[key]);
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]);
});
// Commented out as we investigate whether this is only needed for image proxy
// expect(output.init.imagetools_cors_hosts).toMatchObject([props.lmsEndpointUrl]);

View File

@@ -40,6 +40,7 @@ export const TextEditor = ({
onClose,
// redux
isRaw,
isLibrary,
blockValue,
lmsEndpointUrl,
studioEndpointUrl,
@@ -76,6 +77,7 @@ export const TextEditor = ({
initializeEditor,
lmsEndpointUrl,
studioEndpointUrl,
isLibrary,
images,
setSelection: imageSelection.setSelection,
clearSelection: imageSelection.clearSelection,
@@ -90,13 +92,15 @@ export const TextEditor = ({
onClose={onClose}
>
<div className="editor-body h-75 overflow-auto">
<ImageUploadModal
isOpen={isImgOpen}
close={closeImgModal}
editorRef={editorRef}
images={images}
{...imageSelection}
/>
{isLibrary ? null : (
<ImageUploadModal
isOpen={isImgOpen}
close={closeImgModal}
editorRef={editorRef}
images={images}
{...imageSelection}
/>
)}
<SourceCodeModal
isOpen={isSourceCodeOpen}
close={closeSourceCodeModal}
@@ -125,6 +129,7 @@ export const TextEditor = ({
TextEditor.defaultProps = {
blockValue: null,
isRaw: null,
isLibrary: null,
lmsEndpointUrl: null,
studioEndpointUrl: null,
images: null,
@@ -141,6 +146,7 @@ TextEditor.propTypes = {
blockFailed: PropTypes.bool.isRequired,
initializeEditor: PropTypes.func.isRequired,
isRaw: PropTypes.bool,
isLibrary: PropTypes.bool,
imagesFinished: PropTypes.bool,
images: PropTypes.shape({}),
// inject
@@ -153,6 +159,7 @@ export const mapStateToProps = (state) => ({
studioEndpointUrl: selectors.app.studioEndpointUrl(state),
blockFailed: selectors.requests.isFailed(state, { requestKey: RequestKeys.fetchBlock }),
isRaw: selectors.app.isRaw(state),
isLibrary: selectors.app.isLibrary(state),
imagesFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchImages }),
images: selectors.app.images(state),
});

View File

@@ -71,6 +71,7 @@ jest.mock('../../data/redux', () => ({
studioEndpointUrl: jest.fn(state => ({ studioEndpointUrl: state })),
isRaw: jest.fn(state => ({ isRaw: state })),
images: jest.fn(state => ({ images: state })),
isLibrary: jest.fn(state => ({ isLibrary: state })),
},
requests: {
isFailed: jest.fn((state, params) => ({ isFailed: { state, params } })),
@@ -89,6 +90,7 @@ describe('TextEditor', () => {
blockFailed: false,
initializeEditor: jest.fn().mockName('args.intializeEditor'),
isRaw: false,
isLibrary: false,
imagesFinished: true,
images: { sOmEuiMAge: { staTICUrl: '/assets/sOmEuiMAge' } },
// inject
@@ -117,7 +119,11 @@ describe('TextEditor', () => {
test('block failed to load, Toast is shown', () => {
expect(shallow(<TextEditor {...props} blockFailed />)).toMatchSnapshot();
});
test('ImageUploadModal is not rendered', () => {
expect(shallow(<TextEditor {...props} isLibrary />)).toMatchSnapshot();
});
});
describe('mapStateToProps', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
test('blockValue from app.blockValue', () => {

View File

@@ -3,53 +3,64 @@ import { buttons, plugins } from '../../data/constants/tinyMCE';
const mapToolbars = toolbars => toolbars.map(toolbar => toolbar.join(' ')).join(' | ');
export default StrictDict({
plugins: [
plugins.link,
plugins.lists,
plugins.codesample,
plugins.emoticons,
plugins.table,
plugins.hr,
plugins.charmap,
plugins.code,
plugins.autoresize,
plugins.image,
plugins.imagetools,
].join(' '),
menubar: false,
toolbar: mapToolbars([
[buttons.undo, buttons.redo],
[buttons.formatSelect],
[buttons.bold, buttons.italic, buttons.underline, buttons.foreColor, buttons.backColor],
[
buttons.align.left,
buttons.align.center,
buttons.align.right,
buttons.align.justify,
],
[
buttons.bullist,
buttons.numlist,
buttons.outdent,
buttons.indent,
],
[buttons.imageUploadButton, buttons.link, buttons.unlink, buttons.blockQuote, buttons.codeBlock],
[buttons.table, buttons.emoticons, buttons.charmap, buttons.hr],
[buttons.removeFormat, buttons.code],
]),
imageToolbar: mapToolbars([
// [buttons.rotate.left, buttons.rotate.right],
// [buttons.flip.horiz, buttons.flip.vert],
[buttons.editImageSettings],
]),
config: {
branding: false,
height: '100%',
menubar: false,
min_height: 500,
toolbar_sticky: true,
relative_urls: true,
convert_urls: false,
},
});
const pluginConfig = (isLibrary) => {
const image = isLibrary ? '' : plugins.image;
const imageTools = isLibrary ? '' : plugins.imagetools;
const imageUploadButton = isLibrary ? '' : buttons.imageUploadButton;
const editImageSettings = isLibrary ? '' : buttons.editImageSettings;
return (
StrictDict({
plugins: [
plugins.link,
plugins.lists,
plugins.codesample,
plugins.emoticons,
plugins.table,
plugins.hr,
plugins.charmap,
plugins.code,
plugins.autoresize,
image,
imageTools,
].join(' '),
menubar: false,
toolbar: mapToolbars([
[buttons.undo, buttons.redo],
[buttons.formatSelect],
[buttons.bold, buttons.italic, buttons.underline, buttons.foreColor, buttons.backColor],
[
buttons.align.left,
buttons.align.center,
buttons.align.right,
buttons.align.justify,
],
[
buttons.bullist,
buttons.numlist,
buttons.outdent,
buttons.indent,
],
[imageUploadButton, buttons.link, buttons.unlink, buttons.blockQuote, buttons.codeBlock],
[buttons.table, buttons.emoticons, buttons.charmap, buttons.hr],
[buttons.removeFormat, buttons.code],
]),
imageToolbar: mapToolbars([
// [buttons.rotate.left, buttons.rotate.right],
// [buttons.flip.horiz, buttons.flip.vert],
[editImageSettings],
]),
config: {
branding: false,
height: '100%',
menubar: false,
min_height: 500,
toolbar_sticky: true,
relative_urls: true,
convert_urls: false,
},
})
);
};
export default pluginConfig;

View File

@@ -82,6 +82,19 @@ export const isRaw = createSelector(
},
);
export const isLibrary = createSelector(
[module.simpleSelectors.learningContextId],
(learningContextId) => {
if (!learningContextId) {
return null;
}
if (learningContextId && learningContextId.startsWith('library-v1')) {
return true;
}
return false;
},
);
export default {
...simpleSelectors,
isInitialized,
@@ -89,4 +102,5 @@ export default {
displayTitle,
analytics,
isRaw,
isLibrary,
};

View File

@@ -140,4 +140,23 @@ describe('app selectors unit tests', () => {
expect(selectors.isRaw.cb(studioViewVisual)).toEqual(false);
});
});
describe('isLibrary', () => {
const learningContextIdLibrary = 'library-v1:name';
const learningContextIdCourse = 'course-v1:name';
it('is memoized based on studioView', () => {
expect(selectors.isLibrary.preSelectors).toEqual([
simpleSelectors.learningContextId,
]);
});
it('returns null if blockId is null', () => {
expect(selectors.isLibrary.cb(null)).toEqual(null);
});
it('returns true if blockId starts with lib', () => {
expect(selectors.isLibrary.cb(learningContextIdLibrary)).toEqual(true);
});
it('returns false if the blockId does not start with lib', () => {
expect(selectors.isLibrary.cb(learningContextIdCourse)).toEqual(false);
});
});
});