UNPKG

communication-react-19

Version:

React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)

275 lines 12.5 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ import { _IMAGE_ATTRIBUTE_INLINE_IMAGE_FILE_NAME_KEY } from "../../../../../acs-ui-common/src"; /* @conditional-compile-remove(rich-text-editor-image-upload) */ import { AttachmentUploadActionType } from '../file-sharing/AttachmentUpload'; /* @conditional-compile-remove(rich-text-editor-image-upload) */ import { _DEFAULT_INLINE_IMAGE_FILE_NAME, SEND_BOX_UPLOADS_KEY_VALUE } from '../../common/constants'; /* @conditional-compile-remove(rich-text-editor-image-upload) */ import { nanoid } from 'nanoid'; /* @conditional-compile-remove(rich-text-editor-image-upload) */ const MAX_INLINE_IMAGE_UPLOAD_SIZE_MB = 20; /* @conditional-compile-remove(rich-text-editor-image-upload) */ const fetchBlobData = (resource, options) => __awaiter(void 0, void 0, void 0, function* () { // default timeout is 30 seconds const { timeout = 30000, abortController } = options; const id = setTimeout(() => { abortController.abort(); }, timeout); const response = yield fetch(resource, Object.assign(Object.assign({}, options), { signal: abortController.signal })); clearTimeout(id); return response; }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @private */ export const getInlineImageData = (image) => __awaiter(void 0, void 0, void 0, function* () { if (image.startsWith('blob') || image.startsWith('http')) { try { const res = yield fetchBlobData(image, { abortController: new AbortController() }); const blobImage = yield res.blob(); return blobImage; } catch (error) { console.error('Error fetching image data', error); return; } } return; }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const getEditBoxMessagesInlineImages = (editBoxInlineImageUploads) => { if (!editBoxInlineImageUploads) { return; } const messagesInlineImagesWithProgress = {}; Object.entries(editBoxInlineImageUploads || {}).map(([messageId, attachmentUploads]) => { const messageUploads = attachmentUploads.map((upload) => { return upload.metadata; }); messagesInlineImagesWithProgress[messageId] = messageUploads; }); return messagesInlineImagesWithProgress; }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const getSendBoxInlineImages = (sendBoxInlineImageUploads) => { var _a; if (!sendBoxInlineImageUploads) { return; } return (_a = sendBoxInlineImageUploads[SEND_BOX_UPLOADS_KEY_VALUE]) === null || _a === void 0 ? void 0 : _a.map((upload) => upload.metadata); }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ const inlineImageUploadHandler = (uploadTasks, adapter, strings) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c; for (const task of uploadTasks) { const uploadTask = task; const image = uploadTask.image; if (!image) { uploadTask.notifyUploadFailed(strings.uploadImageDataNotProvided); continue; } if (image && image.size > MAX_INLINE_IMAGE_UPLOAD_SIZE_MB * 1024 * 1024) { uploadTask.notifyUploadFailed(strings.uploadImageIsTooLarge.replace('{maxImageSize}', `${MAX_INLINE_IMAGE_UPLOAD_SIZE_MB}`)); continue; } const SUPPORTED_FILES = ['jpg', 'jpeg', 'png', 'gif', 'heic', 'webp']; const imageExtension = (_b = (_a = task.metadata) === null || _a === void 0 ? void 0 : _a.name.split('.').pop()) !== null && _b !== void 0 ? _b : ''; if (!SUPPORTED_FILES.includes(imageExtension)) { uploadTask.notifyUploadFailed(strings.uploadImageExtensionIsNotAllowed.replace('{imageExtension}', imageExtension)); continue; } try { const response = yield adapter.uploadImage(image, (_c = task.metadata) === null || _c === void 0 ? void 0 : _c.name); // Use response id as the image src because we need to keep the original image id as a reference to find the image. // Also the html content we send to ChatSDK does not need image src, // it only need the response id to match the uploaded image, url is not needed. uploadTask.notifyUploadCompleted(task.metadata.id, response.id); } catch (error) { console.error(error); uploadTask.notifyUploadFailed(strings.uploadImageFailed); } } }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ const generateUploadTask = (imageAttributes, fileName, messageId, inlineImageUploadActionHandler) => __awaiter(void 0, void 0, void 0, function* () { if (!imageAttributes.src) { console.error('Cannot upload image - Image src is not provided'); return; } if (!imageAttributes.id) { console.error('Cannot upload image - Image id is not provided'); return; } const imageData = yield getInlineImageData(imageAttributes.src); if (!imageData) { return; } const taskId = nanoid(); const uploadTask = { image: imageData, taskId, metadata: { id: imageAttributes.id, name: fileName, url: imageAttributes.src, progress: 0 }, notifyUploadProgressChanged: (value) => { inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Progress, taskId, progress: value, messageId }); }, notifyUploadCompleted: (id, url) => { inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Completed, taskId, id, url, messageId }); }, notifyUploadFailed: (message) => { inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Failed, taskId, message, messageId }); // remove the failed upload task when error banner is auto dismissed after 10 seconds // so the banner won't be shown again on UI re-rendering. setTimeout(() => { inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Remove, id: taskId, messageId }); }, 10 * 1000); } }; return uploadTask; }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const onInsertInlineImageForEditBox = (imageAttributes, fileName, messageId, adapter, handleEditBoxInlineImageUploadAction, chatCompositeStrings) => __awaiter(void 0, void 0, void 0, function* () { const uploadTask = yield generateUploadTask(imageAttributes, fileName, messageId, handleEditBoxInlineImageUploadAction); if (!uploadTask) { return; } handleEditBoxInlineImageUploadAction({ type: AttachmentUploadActionType.Set, newUploads: [uploadTask], messageId }); inlineImageUploadHandler([uploadTask], adapter, chatCompositeStrings); }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const onInsertInlineImageForSendBox = (imageAttributes, fileName, adapter, handleSendBoxInlineImageUploadAction, chatCompositeStrings) => __awaiter(void 0, void 0, void 0, function* () { const uploadTask = yield generateUploadTask(imageAttributes, fileName, SEND_BOX_UPLOADS_KEY_VALUE, handleSendBoxInlineImageUploadAction); if (!uploadTask) { return; } handleSendBoxInlineImageUploadAction({ type: AttachmentUploadActionType.Set, newUploads: [uploadTask], messageId: SEND_BOX_UPLOADS_KEY_VALUE }); inlineImageUploadHandler([uploadTask], adapter, chatCompositeStrings); }); /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const cancelInlineImageUpload = (imageAttributes, imageUploads, messageId, inlineImageUploadActionHandler, adapter) => { var _a; if (!imageAttributes.id) { console.error('Cannot cancel image upload - Image id is not provided'); return; } if (!imageUploads || !imageUploads[messageId]) { deleteExistingInlineImageForEditBox(imageAttributes.id, messageId, adapter); return; } const imageUpload = (_a = imageUploads[messageId]) === null || _a === void 0 ? void 0 : _a.find((upload) => upload.metadata.id === imageAttributes.id); if (!imageUpload || !(imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.id)) { deleteExistingInlineImageForEditBox(imageAttributes.id, messageId, adapter); return; } inlineImageUploadActionHandler({ type: AttachmentUploadActionType.Remove, id: imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.id, messageId }); if ((imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.progress) === 1 && (imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.url)) { // The image id that we got back from the ChatSDK response is stored in the image src attribute, // while the metadata id is the internal image id that we assigned to the image when it was pasted in. deleteInlineImageFromServer(imageUpload === null || imageUpload === void 0 ? void 0 : imageUpload.metadata.url, adapter); } }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ const deleteInlineImageFromServer = (imageId, adapter) => { try { adapter.deleteImage(imageId); } catch (error) { console.error(error); } }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ // This function is used to delete the inline image that existed before editing starts const deleteExistingInlineImageForEditBox = (imageId, messageId, adapter) => { if (messageId !== SEND_BOX_UPLOADS_KEY_VALUE) { deleteInlineImageFromServer(imageId, adapter); } }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const updateContentStringWithUploadedInlineImages = (content, imageUploads, messageId = SEND_BOX_UPLOADS_KEY_VALUE) => { if (!imageUploads || !imageUploads[messageId]) { return content; } const messageUploads = imageUploads[messageId]; const document = new DOMParser().parseFromString(content !== null && content !== void 0 ? content : '', 'text/html'); document.querySelectorAll('img').forEach((img) => { var _a; const uploadInlineImage = messageUploads === null || messageUploads === void 0 ? void 0 : messageUploads.find((upload) => !upload.metadata.error && upload.metadata.progress === 1 && upload.metadata.id === img.id); if (uploadInlineImage) { // ChatSDK uses the respond id provided by the upload response. We store the response id in the image src attribute previously. img.id = (_a = uploadInlineImage.metadata.url) !== null && _a !== void 0 ? _a : img.id; img.src = ''; } }); content = document.body.innerHTML; return content; }; /* @conditional-compile-remove(rich-text-editor-image-upload) */ /** * @internal */ export const getImageFileNameFromAttributes = (imageAttributes) => { const fileName = imageAttributes[_IMAGE_ATTRIBUTE_INLINE_IMAGE_FILE_NAME_KEY]; if (!fileName || fileName === '' || fileName === 'undefined' || fileName === 'null') { return _DEFAULT_INLINE_IMAGE_FILE_NAME; } return fileName; }; //# sourceMappingURL=ImageUploadUtils.js.map