import { EDITOR_CONTENT_MAX_LENGTH } from "../common/constants/settings/notice"; export default class HtmlConverter { /** * editor사용 시 서버로 전송할 때 style tag 추가하거나 변경함(모바일에서도 동일하게 보여지기 위해 추가). * * '' -> '' * '
' -> '
' * '
' -> '
' * * @public * @static * @return string * @param content */ static additionTagStyle(content: string) { let tagStyleWithContent = content; while (tagStyleWithContent.includes("')[0]; tagStyleWithContent = tagStyleWithContent.replaceAll( `class="ql-align-${align}"`, `style="text-align:-webkit-${align}; white-space:pre-wrap;"` ); } while (tagStyleWithContent.includes("ql-indent-")) { const indentSize = Number( tagStyleWithContent.split("ql-indent-")[1].split('">')[0] ); tagStyleWithContent = tagStyleWithContent.replaceAll( `class="ql-indent-${indentSize}"`, `style="text-indent:${indentSize * 3}em; white-space:pre-wrap;"` ); } return tagStyleWithContent; } /** * 서버에서 html tag를 받아와서 보여줄 때 사용(모바일에 보여주기 위해 추가했던 로직 변경)하며 web에서 보여지기 위한 css들이 추가된다. * * '
' -> '
' * "
hello world
" -> "
hello world
" * * @public * @return string * @param content */ static displayHTML(content: string) { let editorContent = content; if ( (!editorContent.includes("text-align") && !editorContent.includes("text-indent")) || editorContent.includes("font-family: nanum-regular, sans-serif;") ) { return editorContent; } while (editorContent.includes("text-align")) { const alignAttribute = editorContent.split("text-align:-webkit-")[1]; const align = alignAttribute.split("; white-space:pre-wrap;")[0]; editorContent = editorContent.replaceAll( `style="text-align:-webkit-${align}; white-space:pre-wrap;"`, `class="ql-align-${align}"` ); } while (editorContent.includes("text-indent")) { const indentSize = Number( editorContent.split("text-indent:")[1].split("em")[0] ); editorContent = editorContent.replaceAll( `style="text-indent:${indentSize}em; white-space:pre-wrap;"`, `class="ql-indent-${indentSize / 3}"` ); } return editorContent; } /** * content에 img태그에 src가 base64로 되어있으면 크기를 재서 return한다. * * '' -> {base64: ["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8AAAAASUVORK5CYII=",]} * * @public * @return string * @param htmlString */ static findImageTagsFromHTML(htmlString: string) { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, "text/html"); const imageTags = doc.getElementsByTagName("img"); const imageSrcList: { base64: string[]; } = { base64: [] }; for (let i = 0; i < imageTags.length; i++) { if (imageTags[i].src.includes("data:image")) { imageSrcList.base64.push(imageTags[i].src); } } return imageSrcList; } /** * editor content 길이를 재서 return한다. * * '' -> 99 * * @public * @return string * @param value * @param imageList */ static getEditorContentLength( value: string, imageList?: { url: string; size: number }[] ) { let imageSize = 0; let textSize = 0; if (value.includes("]+>/g, ""); textSize += new Blob([plainText]).size; if (textSize + imageSize > EDITOR_CONTENT_MAX_LENGTH) { return; } return textSize + imageSize; } /** * img src에 들어있는 base64 string을 blob으로 바꿔 size를 return한다. * * "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8AAAAASUVORK5CYII=" -> 99 * * @static * @public * @return string * @param base64String */ static getImageSizeFromBase64(base64String: string) { const byteNumbers = new Array(base64String.length); for (let i = 0; i < base64String.length; i++) { byteNumbers[i] = base64String.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: "image/jpg" }); return blob.size; } /** * 웹에서 img를 제외한 다른 태그들을 복사할 경우 컨텐츠 뒤에 붙여 return한다. * * @static * @public * @return string * @param event * @param content * @param beforeContent */ static protectWebImagePaste( event: ClipboardEvent, content: string, beforeContent: string ) { const clipboardData: any = event.clipboardData; let newContent; const pastedHTML = clipboardData .getData("text/html") .replace(//g, ""); const plainText = clipboardData.getData("text/plain"); if (pastedHTML && pastedHTML.includes("