Skip to content

Commit

Permalink
feat: add plugins including image-upload (#12)
Browse files Browse the repository at this point in the history
This adds the image upload "plugin" and all the desired built-in plugins.
Per the following two tickets
https://openedx.atlassian.net/browse/TNL-9367
https://openedx.atlassian.net/browse/TNL-9475

I need to add the requisite plugins, as well as a framework for the image upload modal.
  • Loading branch information
connorhaugh authored Feb 14, 2022
1 parent 2f931b5 commit eef3034
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 24 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
},
"dependencies": {
"@tinymce/tinymce-react": "^3.13.0",
"tinymce": "^5.10.2",
"babel-polyfill": "6.26.0",
"react-responsive": "8.2.0",
"react-transition-group": "4.4.2"
Expand Down
18 changes: 7 additions & 11 deletions src/editors/EditorPage.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ModalDialog } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import TextEditor from './TextEditor/TextEditor';
import VideoEditor from './VideoEditor/VideoEditor';
Expand Down Expand Up @@ -41,20 +40,17 @@ export default function EditorPage({
blockId={blockId}
studioEndpointUrl={studioEndpointUrl}
>
<ModalDialog
title={blockType}
isOpen
size="fullscreen"
onClose={() => {}}
hasCloseButton={false}
variant="dark"
>
<div className="d-flex flex-column vh-100">
<div className="d-flex flex-column vh-100">
<div
className="pgn__modal-fullscreen"
role="dialog"
aria-label={blockType}
>
<EditorHeader title={blockType} />
{selectEditor(blockType)}
<EditorFooter />
</div>
</ModalDialog>
</div>
</EditorPageProvider>
);
}
Expand Down
51 changes: 51 additions & 0 deletions src/editors/TextEditor/ImageUpload/Wizard/ImageUploadModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ModalDialog, ActionRow, Button } from '@edx/paragon';

const ImageUploadModal = ({ isOpen, close }) => (
<ModalDialog
title="My dialog"
isOpen={isOpen}
onClose={close}
size="lg"
variant="default"
hasCloseButton
isFullscreenOnMobile
>
<ModalDialog.Header>
<ModalDialog.Title>
Im a dialog box
</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>
<p>
Im baby palo santo ugh celiac fashion axe.
La croix lo-fi venmo whatever.
Beard man braid migas single-origin coffee forage ramps.
Tumeric messenger bag bicycle rights wayfarers, try-hard cronut blue bottle health goth.
Sriracha tumblr cardigan, cloud bread succulents tumeric copper mug marfa semiotics woke next
level organic roof party +1 try-hard.
</p>
</ModalDialog.Body>
<ModalDialog.Footer>
<ActionRow>
<ModalDialog.CloseButton variant="tertiary">
Cancel
</ModalDialog.CloseButton>
<Button variant="primary">
A button
</Button>
</ActionRow>
</ModalDialog.Footer>
</ModalDialog>
);

ImageUploadModal.propTypes = {
isOpen: PropTypes.bool,
close: PropTypes.func,
};
ImageUploadModal.defaultProps = {
isOpen: false,
close: () => {},
};
export default ImageUploadModal;
48 changes: 35 additions & 13 deletions src/editors/TextEditor/TextEditor.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
import React, { useContext } from 'react';
import { Spinner, Toast } from '@edx/paragon';
import { Editor } from '@tinymce/tinymce-react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import {
useToggle, Spinner, Toast,
} from '@edx/paragon';
import EditorPageContext from '../EditorPageContext';
import { ActionStates } from '../data/constants';
import ImageUploadModal from './ImageUpload/Wizard/ImageUploadModal';

import 'tinymce';
import 'tinymce/themes/silver';
import 'tinymce/skins/ui/oxide/skin.css';
import 'tinymce/icons/default';
import 'tinymce/plugins/link';
import 'tinymce/plugins/table';
import 'tinymce/plugins/codesample';
import 'tinymce/plugins/emoticons';
import 'tinymce/plugins/emoticons/js/emojis';
import 'tinymce/plugins/charmap';
import 'tinymce/plugins/code';
import 'tinymce/plugins/autoresize';

const TextEditor = () => {
const {
blockValue, blockError, blockLoading, editorRef,
} = useContext(EditorPageContext);

const [isImageUploadModalOpen, openUploadModal, closeUploadModal] = useToggle(false);

return (
<div className="editor-body h-75">
<ImageUploadModal isOpen={isImageUploadModalOpen} close={closeUploadModal} />
<Toast show={blockError != null} onClose={() => {}}>
<FormattedMessage
id="authoring.texteditor.load.error"
Expand All @@ -27,24 +46,27 @@ const TextEditor = () => {
)
: (
<Editor
onInit={(evt, editor) => { editorRef.current = editor; }}
onInit={(evt, editor) => {
editorRef.current = editor;
}}
initialValue={blockValue ? blockValue.data.data : ''}
init={{
height: '100%',
setup: (editor) => {
editor.ui.registry.addButton('imageuploadbutton', {
icon: 'image',
onAction: () => openUploadModal(),
});
},
plugins: 'link codesample emoticons table charmap code autoresize',
menubar: false,
plugins: [
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visual blocks code fullscreen',
'insertdatetime media table paste code help wordcount',
'autoresize',
],
toolbar: 'undo redo | formatselect | '
+ 'bold italic backcolor | alignleft aligncenter '
+ 'alignright alignjustify | bullist numlist outdent indent | '
+ 'removeformat | help',
+ 'alignright alignjustify | bullist numlist outdent indent |'
+ 'imageuploadbutton | link | emoticons | table | codesample | charmap |'
+ 'removeformat | hr |code',
height: '100%',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
max_height: 900,
min_height: 700,
min_height: 1000,
branding: false,
}}
/>
Expand Down
16 changes: 16 additions & 0 deletions src/setupTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ import 'babel-polyfill';

Enzyme.configure({ adapter: new Adapter() });

/* need to mock window for tinymce on import, as it is JSDOM incompatible */

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});

// These configuration values are usually set in webpack's EnvironmentPlugin however
// Jest does not use webpack so we need to set these so for testing
process.env.ACCESS_TOKEN_COOKIE_NAME = 'edx-jwt-cookie-header-payload';
Expand Down

0 comments on commit eef3034

Please sign in to comment.