UNPKG

@syncfusion/ej2-richtexteditor

Version:
769 lines (768 loc) 34 kB
import * as EVENTS from '../../common/constant'; import { pasteCleanupGroupingTags } from '../../common/config'; import { createElement, isNullOrUndefined as isNOU, detach, Browser, extend, getUniqueID } from '@syncfusion/ej2-base'; import { convertToBlob } from '../../common/util'; /** * PasteCleanup common action * * @hidden */ var PasteCleanupAction = /** @class */ (function () { function PasteCleanupAction(parent, pasteModel) { this.parent = parent; this.pasteModel = pasteModel; this.addEventListener(); } PasteCleanupAction.prototype.addEventListener = function () { this.parent.observer.on(EVENTS.INTERNAL_DESTROY, this.destroy, this); }; PasteCleanupAction.prototype.removeEventListener = function () { this.parent.observer.off(EVENTS.INTERNAL_DESTROY, this.destroy); }; /** * Updates the paste cleanup object with refreshed editor configuration and callback methods * * @param {IPasteModel} updatedPasteModel - The updated paste model with latest configuration * @returns {void} - This method does not return a value * @public * @hidden */ PasteCleanupAction.prototype.updatePasteCleanupModel = function (updatedPasteModel) { this.pasteModel = updatedPasteModel; }; /** * Extracts file from clipboard data if available * * @param {NotifyArgs} e - The notification arguments containing clipboard data * @returns {File} The extracted file from clipboard * @public * @hidden */ PasteCleanupAction.prototype.extractFileFromClipboard = function (e) { if (!e || !e.args || !e.args.clipboardData || e.args.clipboardData.items.length === 0) { return null; } var items = e.args.clipboardData.items; var file = items[0].getAsFile(); if (file !== null) { return file; } return !isNOU(items[1]) ? items[1].getAsFile() : null; }; /** * Splits text by double line breaks and formats it according to editor's enter key configuration * * @param {string} value - The text value to be split and formatted * @returns {string} The formatted text with proper line breaks * @public * @hidden */ PasteCleanupAction.prototype.splitBreakLine = function (value) { var enterSplitText = value.split(/\r\n\r\n|\n\n/g); var finalText = ''; var startNode = this.getHtmlNode(true); var endNode = this.getHtmlNode(false); var isBrFormat = this.pasteModel.enterKey === 'BR'; for (var i = 0; i < enterSplitText.length; i++) { var content = enterSplitText[i]; var contentWithSpace = this.normalizeSpacesForHtml(content); var contentWithLineBreak = contentWithSpace.replace(/\r\n|\n/g, '<br>'); if (i === 0) { if (isBrFormat && (i !== enterSplitText.length - 1 || contentWithLineBreak.endsWith('<br>'))) { if (i !== enterSplitText.length - 1) { finalText += (contentWithLineBreak + endNode + endNode); } else { finalText += (contentWithLineBreak + endNode); } } else { finalText += contentWithLineBreak; // In order to merge the content in current line. No P/Div tag is added. } } else { if (isBrFormat) { if (contentWithLineBreak.endsWith('<br>') || (contentWithLineBreak === '' && i === enterSplitText.length - 1)) { finalText += (contentWithLineBreak + endNode); } else if (i === enterSplitText.length - 1) { finalText += contentWithLineBreak; } else { finalText += (contentWithLineBreak + endNode + endNode); } } else { if (contentWithLineBreak.trim() === '') { finalText += '<br>'; } finalText += startNode + contentWithLineBreak + endNode; } } } return finalText; }; /** * Gets HTML node tag based on enterKey settings and whether it's start or end tag * * @param {boolean} isStartTag - Indicates whether to return start tag (true) or end tag (false) * @returns {string} The HTML node tag string * @public * @hidden */ PasteCleanupAction.prototype.getHtmlNode = function (isStartTag) { if (this.pasteModel.enterKey === 'P') { return isStartTag ? '<p>' : '</p>'; } else if (this.pasteModel.enterKey === 'DIV') { return isStartTag ? '<div>' : '</div>'; } return isStartTag ? '' : '<br>'; }; /** * Converts spaces and tabs in text to HTML space entities. * * @param {string} text - The input text containing spaces and tabs to be converted * @returns {string} The text with spaces and tabs converted to HTML entities * @public * @hidden */ PasteCleanupAction.prototype.normalizeSpacesForHtml = function (text) { var spacedContent = ''; if (text === '') { return text; } var lineBreakSplitText = text.split(' '); for (var i = 0; i < lineBreakSplitText.length; i++) { var currentText = lineBreakSplitText[i]; if (currentText === '') { spacedContent += '&nbsp;'; } else if (currentText === '\t') { spacedContent += '&nbsp;&nbsp;&nbsp;&nbsp;'; } else { if (i > 0 && i < lineBreakSplitText.length) { spacedContent += ' '; } spacedContent += currentText; } } spacedContent = spacedContent.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;'); spacedContent = spacedContent.replace(/&nbsp;&nbsp;/g, '&nbsp; '); return spacedContent; }; /** * Converts base64 into file data. * * @param {string} base64 - The base64 encoded string to convert * @param {string} filename - The name for the resulting file * @returns {File} The converted file object * @public * @hidden */ PasteCleanupAction.prototype.base64ToFile = function (base64, filename) { var baseStr = base64.split(','); var typeStr = baseStr[0].match(/:(.*?);/)[1]; var extension = typeStr.split('/')[1]; var decodeStr = atob(baseStr[1]); var strLen = decodeStr.length; var decodeArr = new Uint8Array(strLen); while (strLen--) { decodeArr[strLen] = decodeStr.charCodeAt(strLen); } if (Browser.isIE || navigator.appVersion.indexOf('Edge') > -1) { var blob = new Blob([decodeArr], { type: extension }); extend(blob, { name: filename + '.' + (!isNOU(extension) ? extension : '') }); return blob; } else { return new File([decodeArr], filename + '.' + (!isNOU(extension) ? extension : ''), { type: extension }); } }; /** * Sets the image opacity to indicate upload in progress. * * @param {Element} imgElem - The image element to modify opacity for * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.setImageOpacity = function (imgElem) { imgElem.style.opacity = '0.5'; }; /** * Creates the popup element for upload progress. * * @returns {HTMLElement} The created popup element for displaying upload progress * @public * @hidden */ PasteCleanupAction.prototype.createPopupElement = function () { var popupEle = createElement('div'); this.pasteModel.rootContainer.appendChild(popupEle); return popupEle; }; /** * Converts base64 image sources to blob URLs. * * @param {NodeListOf<HTMLImageElement>} allImgElm - Collection of image elements to process * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.getBlob = function (allImgElm) { for (var i = 0; i < allImgElm.length; i++) { var imgSrc = allImgElm[i].getAttribute('src'); if (!isNOU(imgSrc) && imgSrc.split(',')[0].indexOf('base64') >= 0) { var blobUrl = URL.createObjectURL(convertToBlob(imgSrc)); allImgElm[i].setAttribute('src', blobUrl); } } }; /** * Removes Apple-specific line break elements from the HTML content. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to clean * @returns {HTMLElement} The cleaned HTML element with Apple-specific line breaks removed * @public * @hidden */ PasteCleanupAction.prototype.cleanAppleClass = function (clipBoardElem) { var appleClassElem = clipBoardElem.querySelectorAll('br.Apple-interchange-newline'); for (var i = 0; i < appleClassElem.length; i++) { detach(appleClassElem[i]); } return clipBoardElem; }; /** * Removes denied tags and attributes as configured by paste cleanup settings. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to clean * @param {boolean} clean - Flag indicating whether cleanup should be performed * @returns {HTMLElement} The cleaned HTML element with denied tags and attributes removed * @public * @hidden */ PasteCleanupAction.prototype.cleanupDeniedTagsAndAttributes = function (clipBoardElem, clean) { if (this.pasteModel.pasteCleanupSettings.deniedTags !== null) { clipBoardElem = this.deniedTags(clipBoardElem); } if (clean) { clipBoardElem = this.deniedAttributes(clipBoardElem, clean); } else if (this.pasteModel.pasteCleanupSettings.deniedAttrs !== null) { clipBoardElem = this.deniedAttributes(clipBoardElem, clean); } return clipBoardElem; }; /** * Removes elements matching denied tags (with or without attribute selectors) from the provided clipboard element. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to process * @returns {HTMLElement} The cleaned HTML element with denied tags removed * @public * @hidden */ PasteCleanupAction.prototype.deniedTags = function (clipBoardElem) { var deniedTags = isNOU(this.pasteModel.pasteCleanupSettings.deniedTags) ? [] : this.pasteModel.pasteCleanupSettings.deniedTags.slice(); deniedTags = this.attributesfilter(deniedTags); deniedTags = this.tagGrouping(deniedTags); for (var i = 0; i < deniedTags.length; i++) { var removableElement = clipBoardElem.querySelectorAll(deniedTags[i]); for (var j = removableElement.length - 1; j >= 0; j--) { var elementToRemove = removableElement[j]; var parentElem = elementToRemove.parentNode; while (elementToRemove.firstChild) { parentElem.insertBefore(elementToRemove.firstChild, elementToRemove); } parentElem.removeChild(elementToRemove); } } return clipBoardElem; }; /** * Parses denied tags array and filters attributes, supporting allowed and denied (! prefix) attributes. * * @param {string[]} deniedTags - Array of denied tag strings to parse and filter * @returns {string[]} The filtered array of attribute strings * @public * @hidden */ PasteCleanupAction.prototype.attributesfilter = function (deniedTags) { for (var i = 0; i < deniedTags.length; i++) { var currentDeniedTag = deniedTags[i]; if (currentDeniedTag.split('[').length > 1) { var userAttributes = currentDeniedTag.split('[')[1].split(']')[0].split(','); var allowedAttributeArray = []; var deniedAttributeArray = []; for (var j = 0; j < userAttributes.length; j++) { var currentUserAttrs = userAttributes[j]; if (userAttributes[j].indexOf('!') < 0) { allowedAttributeArray.push(currentUserAttrs.trim()); } else { deniedAttributeArray.push(currentUserAttrs.split('!')[1].trim()); } } var allowedAttribute = allowedAttributeArray.length > 1 ? (allowedAttributeArray.join('][')) : (allowedAttributeArray.join()); var deniedAttribute = deniedAttributeArray.length > 1 ? deniedAttributeArray.join('][') : (deniedAttributeArray.join()); if (deniedAttribute.length > 0) { var select = allowedAttribute !== '' ? currentDeniedTag.split('[')[0] + '[' + allowedAttribute + ']' : currentDeniedTag.split('[')[0]; deniedTags[i] = select + ':not([' + deniedAttribute + '])'; } else { deniedTags[i] = currentDeniedTag.split('[')[0] + '[' + allowedAttribute + ']'; } } } return deniedTags; }; /** * Expands denied tag list by including related tags based on grouping definitions. * * @param {string[]} deniedTags - Array of denied tag strings to expand * @returns {string[]} The expanded array of denied tags including related tags * @public * @hidden */ PasteCleanupAction.prototype.tagGrouping = function (deniedTags) { var groupingTags = deniedTags.slice(); var keys = Object.keys(pasteCleanupGroupingTags); var values = keys.map(function (key) { return pasteCleanupGroupingTags["" + key]; }); var addTags = []; for (var i = 0; i < groupingTags.length; i++) { var currrentGroupTag = groupingTags[i]; var groupIndex = keys.indexOf(currrentGroupTag); //The value split using '[' because to retrieve the tag name from the user given format which may contain tag with attributes if (currrentGroupTag.split('[').length > 1) { currrentGroupTag = currrentGroupTag.split('[')[0].trim(); } if (keys.indexOf(groupingTags[i]) > -1) { for (var j = 0; j < values[groupIndex].length; j++) { if (groupingTags.indexOf(values[groupIndex][j]) < 0 && addTags.indexOf(values[groupIndex][j]) < 0) { addTags.push(values[groupIndex][j]); } } } } return deniedTags = deniedTags.concat(addTags); }; /** * Removes denied attributes from all elements in the provided clipboard element. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to process * @param {boolean} clean - Flag indicating whether cleanup should be performed * @returns {HTMLElement} The cleaned HTML element with denied attributes removed * @public * @hidden */ PasteCleanupAction.prototype.deniedAttributes = function (clipBoardElem, clean) { var deniedAttrs = isNOU(this.pasteModel.pasteCleanupSettings.deniedAttrs) ? [] : this.pasteModel.pasteCleanupSettings.deniedAttrs.slice(); if (clean) { deniedAttrs.push('style'); } for (var i = 0; i < deniedAttrs.length; i++) { var currentDeniedAttr = deniedAttrs[i]; var removableAttrElement = clipBoardElem. querySelectorAll('[' + currentDeniedAttr + ']'); for (var j = 0; j < removableAttrElement.length; j++) { removableAttrElement[j].removeAttribute(currentDeniedAttr); } } return clipBoardElem; }; /** * Filters the inline 'style' attribute on all elements within the clipboard root element, leaving only allowed CSS style properties. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to process * @returns {HTMLElement} The processed HTML element with filtered style attributes * @public * @hidden */ PasteCleanupAction.prototype.allowedStyle = function (clipBoardElem) { var allowedStyleProps = isNOU(this.pasteModel.pasteCleanupSettings.allowedStyleProps) ? [] : this.pasteModel.pasteCleanupSettings.allowedStyleProps.slice(); allowedStyleProps.push('list-style-type', 'list-style'); var elementsWithStyle = clipBoardElem.querySelectorAll('[style]'); for (var i = 0; i < elementsWithStyle.length; i++) { var currentStyleElem = elementsWithStyle[i]; var allowedStyleValue = ''; var allowedStyleValueArray = []; var styleValue = currentStyleElem.getAttribute('style').split(';'); for (var k = 0; k < styleValue.length; k++) { if (allowedStyleProps.indexOf(styleValue[k].split(':')[0].trim()) >= 0) { allowedStyleValueArray.push(styleValue[k]); } } currentStyleElem.removeAttribute('style'); allowedStyleValue = allowedStyleValueArray.join(';').trim() === '' ? allowedStyleValueArray.join(';') : allowedStyleValueArray.join(';') + ';'; if (allowedStyleValue) { currentStyleElem.style.cssText += allowedStyleValue; } } return clipBoardElem; }; /** * Adds paste class to images and applies image properties. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content with images to process * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.setImageClassAndProps = function (clipBoardElem) { var allImg = clipBoardElem.getElementsByTagName('img'); for (var i = 0, len = allImg.length; i < len; i++) { if (allImg[i].getAttribute('src') !== null) { allImg[i].className += ' pasteContent_Img'; } this.setImageProperties(allImg[i]); } this.addTempClass(clipBoardElem); }; /** * Sets width, height, and min/max styles for inserted images based on editor settings. * * @param {HTMLImageElement} allImg - The image element to apply properties to * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.setImageProperties = function (allImg) { if (this.pasteModel.insertImageSettings.width !== 'auto') { allImg.setAttribute('width', this.pasteModel.insertImageSettings.width); } if (this.pasteModel.insertImageSettings.minWidth !== '0' && this.pasteModel.insertImageSettings.minWidth !== 0) { allImg.style.minWidth = this.pasteModel.insertImageSettings.minWidth.toString(); } if (this.pasteModel.insertImageSettings.maxWidth !== null) { allImg.style.maxWidth = this.pasteModel.getInsertImgMaxWidth().toString(); } if (this.pasteModel.insertImageSettings.height !== 'auto') { allImg.setAttribute('height', this.pasteModel.insertImageSettings.height); } if (this.pasteModel.insertImageSettings.minHeight !== '0' && this.pasteModel.insertImageSettings.minHeight !== 0) { allImg.style.minHeight = this.pasteModel.insertImageSettings.minHeight.toString(); } if (this.pasteModel.insertImageSettings.maxHeight !== null) { allImg.style.maxHeight = this.pasteModel.insertImageSettings.maxHeight.toString(); } }; /** * Temporarily adds a CSS class to all children of the clipboard element. * * @param {HTMLElement} clipBoardElem - The HTML element containing clipboard content to add temporary classes to * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.addTempClass = function (clipBoardElem) { var allChild = clipBoardElem.children; for (var i = 0; i < allChild.length; i++) { allChild[i].classList.add('pasteContent_RTE'); } }; /** * Checks if there is any <picture> element present. * * @param {HTMLElement} clipBoardElem - The HTML element to check for picture elements * @returns {boolean} True if picture element is found, false otherwise * @public * @hidden */ PasteCleanupAction.prototype.hasPictureElement = function (clipBoardElem) { return clipBoardElem.getElementsByTagName('picture').length > 0; }; /** * Processes all <picture> elements to resolve relative srcset attributes in <source> tags * using the base URI or the origin of the image source. * * @param {HTMLElement} clipBoardElem - The HTML element containing picture elements to process * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.processPictureElement = function (clipBoardElem) { var pictureElems = clipBoardElem.querySelectorAll('picture'); var base = this.pasteModel.getDocument().baseURI; for (var i = 0; i < pictureElems.length; i++) { var imgElem = pictureElems[i].querySelector('img'); var sourceElems = pictureElems[i].querySelectorAll('source'); if (imgElem && imgElem.getAttribute('src')) { var srcValue = imgElem.getAttribute('src'); var url = srcValue.indexOf('http') > -1 ? new URL(srcValue) : new URL(srcValue, base); for (var j = 0; j < sourceElems.length; j++) { var srcset = sourceElems[j].getAttribute('srcset'); if (srcset) { if (srcset.indexOf('http') === -1) { var fullPath = url.origin + srcset; sourceElems[j].setAttribute('srcset', fullPath); } } } } } }; /** * Returns true if node has any content (text, images, or table). * * @param {HTMLElement} clipBoardElem - The HTML element to check for content * @returns {boolean} True if the element has content, false otherwise * @public * @hidden */ PasteCleanupAction.prototype.hasContentToPaste = function (clipBoardElem) { var hasText = (clipBoardElem.textContent !== '') && (clipBoardElem.textContent.replace(/\u200B/g, '').trim() !== ''); var hasImg = clipBoardElem.getElementsByTagName('img').length > 0; var hasTable = clipBoardElem.getElementsByTagName('table').length > 0; var hasBr = clipBoardElem.getElementsByTagName('br').length > 0; return hasText || hasImg || hasTable || hasBr; }; /** * Extracts base64-encoded images from the HTML content and converts them to File objects for upload. * * @param {HTMLElement} tempWrapperElem - The HTML element containing base64 images to extract * @returns {FileInfo[]} Array of FileInfo objects containing the converted file data * @public * @hidden */ PasteCleanupAction.prototype.collectBase64ImageFiles = function (tempWrapperElem) { var filesData = []; if (!isNOU(tempWrapperElem.querySelector('img'))) { var imgElem = tempWrapperElem.querySelectorAll('img'); var base64Src = []; var imgName = []; var uploadImg = []; for (var i = 0; i < imgElem.length; i++) { var src = imgElem[i].getAttribute('src'); if (src && src.split(',')[0].indexOf('base64') >= 0) { base64Src.push(src); imgName.push(getUniqueID('rte_image')); uploadImg.push(imgElem[i]); } } var fileList = []; var currentData = void 0; for (var i = 0; i < base64Src.length; i++) { fileList.push(this.base64ToFile(base64Src[i], imgName[i])); currentData = { name: fileList[i].name, rawFile: fileList[i], size: fileList[i].size, type: fileList[i].type, status: '', validationMessages: { minSize: '', maxSize: '' }, statusCode: '1' }; filesData.push(currentData); } } return filesData; }; /** * Adds appropriate class names to tables in the pasted content for formatting or standardization. * * @param {HTMLElement} element - The HTML element containing tables to add classes to * @param {string} [source] - Optional source parameter for context-specific formatting * @returns {HTMLElement} The processed HTML element with table classes added * @public * @hidden */ PasteCleanupAction.prototype.addTableClass = function (element, source) { var tableElements = element.querySelectorAll('table'); for (var i = 0; i < tableElements.length; i++) { var table = tableElements[i]; var tableParentElement = table.parentElement; var isMSTeamsTable = tableParentElement && (tableParentElement.nodeName === 'FIGURE'); var hasCustomClass = table.classList.length > 0 && table.classList.contains('e-rte-custom-table'); if (hasCustomClass) { continue; // Skip the custom table class } if (this.pasteModel.pasteCleanupSettings.keepFormat && source && !isMSTeamsTable) { table.classList.add('e-rte-paste-' + source + '-table'); } else if (!table.classList.contains('e-rte-table')) { table.classList.add('e-rte-table'); } // Remove empty next sibling node (if any) var tableNextSibling = table.nextSibling; var shouldRemoveNextSibling = isNOU(table.nextElementSibling) && tableNextSibling && tableNextSibling.textContent.trim() === ''; if (shouldRemoveNextSibling) { detach(tableNextSibling); } } return element; }; /** * Removes the temporary CSS class from elements and their class attribute if empty. * * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.removeTempClass = function () { var classElm = this.pasteModel.getEditPanel().querySelectorAll('.pasteContent_RTE'); for (var i = 0; i < classElm.length; i++) { classElm[i].classList.remove('pasteContent_RTE'); if (classElm[i].getAttribute('class') === '') { classElm[i].removeAttribute('class'); } } }; /** * Handles image cropping and blob-to-base64 conversion for images within the provided element. * * @param {HTMLElement} element - The HTML element containing images to be processed. * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.cropImageHandler = function (element) { var croppedImgs = element.querySelectorAll('.e-img-cropped'); if (croppedImgs.length > 0) { this.processCroppedImages(croppedImgs); } else { this.handleBlobOrUpload(); } }; /** * Processes all images marked for cropping within the editor element using a for loop. * * @param {NodeListOf<HTMLImageElement>} croppedImgs - A NodeList of HTML image elements that are marked for cropping. * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.processCroppedImages = function (croppedImgs) { var _this = this; var _loop_1 = function (i) { var currentImage = croppedImgs[i]; var src = currentImage.getAttribute('src'); if (src && src.split(',')[0].indexOf('base64') >= 0) { var cropData_1 = this_1.pasteModel.getCropImageData()[i]; var tempImage_1 = new Image(); tempImage_1.src = src; tempImage_1.onload = function () { var wRatio = cropData_1.goalWidth / tempImage_1.naturalWidth; var hRatio = cropData_1.goalHeight / tempImage_1.naturalHeight; var cropLeft = cropData_1.cropLength / wRatio; var cropTop = cropData_1.cropTop / hRatio; var cropWidth = (cropData_1.goalWidth - cropData_1.cropLength - cropData_1.cropR) / wRatio; var cropHeight = (cropData_1.goalHeight - cropData_1.cropTop - cropData_1.cropB) / hRatio; var canvas = document.createElement('canvas'); canvas.width = cropWidth; canvas.height = cropHeight; var ctx = canvas.getContext('2d'); if (ctx) { // Draw the cropped portion of the image onto the canvas ctx.drawImage(tempImage_1, cropLeft, cropTop, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight); // Update the image source with the cropped image data currentImage.setAttribute('src', canvas.toDataURL('image/png')); currentImage.classList.remove('e-img-cropped'); _this.pasteModel.imageUpload(); if (_this.pasteModel.iframeSettings.enable) { _this.pasteModel.updateValue(); } } }; } }; var this_1 = this; for (var i = 0; i < croppedImgs.length; i++) { _loop_1(i); } }; /** * Handles blob image conversion to base64 (based on clipboard content) or the general image upload/updateValue logic. * * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.handleBlobOrUpload = function () { var _this = this; var inputElement = this.pasteModel.getEditPanel(); var inputImgs = inputElement.querySelectorAll('img'); var needsBlobConversion = inputImgs.length > 0 && inputImgs[0].src.startsWith('blob') && !isNOU(this.pasteModel.insertImageSettings.saveUrl) && !isNOU(this.pasteModel.insertImageSettings.path); if (needsBlobConversion) { // Based on the information in your clipboard, convert blob src 'img' elements to base64 if needed this.convertBlobToBase64(inputElement); this.iframeUploadTime = setTimeout(function () { _this.pasteModel.imageUpload(); if (_this.pasteModel.iframeSettings.enable) { _this.pasteModel.updateValue(); } }, 20); } else { this.pasteModel.imageUpload(); if (this.pasteModel.iframeSettings.enable && !this.pasteModel.enableXhtml) { this.pasteModel.updateValue(); } } }; /** * Converts all <img> elements with a blob URL source inside the provided element to base64. * * @param {HTMLElement} element - The HTML element containing image elements to be converted from blob URLs to base64. * @returns {void} Nothing is returned * @public * @hidden */ PasteCleanupAction.prototype.convertBlobToBase64 = function (element) { var imgElem = element.querySelectorAll('img'); var _loop_2 = function (i) { var imgUrl = imgElem[i].getAttribute('src'); if (imgUrl && imgUrl.startsWith('blob')) { var tempImage_2 = new Image(); // Once the blob image is loaded, draw it on a canvas and get the base64 string var onImageLoadEvent_1 = function () { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = tempImage_2.width; canvas.height = tempImage_2.height; ctx.drawImage(tempImage_2, 0, 0); var base64String = canvas.toDataURL('image/png'); // Replace the <img> src with the base64 imgElem[i].src = base64String; tempImage_2.removeEventListener('load', onImageLoadEvent_1); }; tempImage_2.src = imgUrl; tempImage_2.addEventListener('load', onImageLoadEvent_1); } }; for (var i = 0; i < imgElem.length; i++) { _loop_2(i); } }; /** * Cleans up resources when the component is destroyed * * @returns {void} - No return value * @public */ PasteCleanupAction.prototype.destroy = function () { if (this.iframeUploadTime) { clearTimeout(this.iframeUploadTime); this.iframeUploadTime = null; } this.removeEventListener(); }; return PasteCleanupAction; }()); export { PasteCleanupAction };