Skip to content

Commit

Permalink
feat: Support TinyMCE image upload for library components
Browse files Browse the repository at this point in the history
  • Loading branch information
kdmccormick committed Oct 24, 2024
1 parent 3d8d248 commit 5eb6a48
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 11 deletions.
51 changes: 44 additions & 7 deletions src/editors/data/redux/thunkActions/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RequestKeys } from '../../constants/requests';
import api, { loadImages } from '../../services/cms/api';
import { actions as requestsActions } from '../requests';
import { selectors as appSelectors } from '../app';
import { isLibraryKey } from '../../../../generic/key-utils';

// This 'module' self-import hack enables mocking during tests.
// See src/editors/decisions/0005-internal-editor-testability-decisions.md. The whole approach to how hooks are tested
Expand Down Expand Up @@ -133,15 +134,51 @@ export const uploadAsset = ({ asset, ...rest }) => (dispatch, getState) => {
};

export const fetchImages = ({ pageNumber, ...rest }) => (dispatch, getState) => {
const learningContextId = selectors.app.learningContextId(getState());
const studioEndpointUrl = selectors.app.studioEndpointUrl(getState());
dispatch(module.networkRequest({
requestKey: RequestKeys.fetchImages,
promise: api
.fetchImages({
pageNumber,
studioEndpointUrl: selectors.app.studioEndpointUrl(getState()),
learningContextId: selectors.app.learningContextId(getState()),
})
.then(({ data }) => ({ images: loadImages(data.assets), imageCount: data.totalCount })),
promise: isLibraryKey(learingContextId) ? (
api
.fetchImages({ pageNumber, studioEndpointUrl, learningContextId })
.then(({ data }) => ({ images: loadImages(data.assets), imageCount: data.totalCount }))
) : (
api
.fetchLibraryBlockAssets({
pageNumber,
studioEndpointUrl,
blockId: selectors.app.blockId(getState()),
})
.then(({ data }) => {
const imageTypes = {
png: 'image/png',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
};
const images = data.files.reduce(
(obj, file) => {
const fileName = file.path.replace(/^.*[\\/]/, '');
const fileExt = file.path.split('.').pop().toLowerCase();
return imageTypes.hasOwnProperty(fileExt) ? {
...obj,
[fileName]: {
displayName: fileName,
contentType: imageTypesByExtension[fileExt],
dateAdded: '',
url: file.url,
externalUrl: file.url,
portableUrl: file.path,
thumbnail: file.url,
id: file.path,
locked: false,
},
} : obj;
},
{},
);
return { images, imageCount: images.keys().length };
})
),
...rest,
}));
};
Expand Down
8 changes: 8 additions & 0 deletions src/editors/data/services/cms/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ export const apiMethods = {
fetchStudioView: ({ blockId, studioEndpointUrl }) => get(
urls.blockStudioView({ studioEndpointUrl, blockId }),
),
fetchLibraryBlockAssets: ({
blockId,
studioEndpointUrl,
pageNumber,
}): Promise<{ data: AssetResponse & Pagination }> => get(
urls.libraryBlockAssets({ studioEndpointUrl, blockId }),
{ page: pageNumber },
),
fetchImages: ({
learningContextId,
studioEndpointUrl,
Expand Down
4 changes: 4 additions & 0 deletions src/editors/data/services/cms/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export const blockStudioView = (({ studioEndpointUrl, blockId }) => (
: `${studioEndpointUrl}/api/xblock/v2/xblocks/${blockId}/view/studio_view/`
)) satisfies UrlFunction;

export const libraryBlockAssets = (({ studioEndpointUrl, blockId }) => (
`${studioEndpointUrl}/libraries/v2/blocks/${blockId}/assets`
)) satisfies UrlFunction;

export const courseAssets = (({ studioEndpointUrl, learningContextId }) => (
`${studioEndpointUrl}/assets/${learningContextId}/`
)) satisfies UrlFunction;
Expand Down
8 changes: 4 additions & 4 deletions src/editors/sharedComponents/TinyMceWidget/pluginConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { buttons, plugins } from '../../data/constants/tinyMCE';
const mapToolbars = toolbars => toolbars.map(toolbar => toolbar.join(' ')).join(' | ');

const pluginConfig = ({ isLibrary, placeholder, editorType }) => {
const image = isLibrary ? '' : plugins.image;
const imageTools = isLibrary ? '' : plugins.imagetools;
const imageUploadButton = isLibrary ? '' : buttons.imageUploadButton;
const editImageSettings = isLibrary ? '' : buttons.editImageSettings;
const { image } = plugins;
const imageTools = plugins.imagetools;
const { imageUploadButton } = buttons;
const { editImageSettings } = buttons;
const codePlugin = editorType === 'text' ? plugins.code : '';
const codeButton = editorType === 'text' ? buttons.code : '';
const labelButton = editorType === 'question' ? buttons.customLabelButton : '';
Expand Down

0 comments on commit 5eb6a48

Please sign in to comment.