UNPKG

@zohodesk/dot

Version:

In this Library, we Provide Some Basic Components to Build Your Application

417 lines (364 loc) 14.7 kB
/***** Libraries *****/ import React, { Component } from 'react'; import { defaultProps } from "./props/defaultProps"; import { propTypes } from "./props/propTypes"; import selectn from 'selectn'; import { Container, Box } from '@zohodesk/components/lib/Layout'; /***** Methods *****/ import { bind, editorContentValidate, fixEncoding, isFileNameSizeInvalid, isImageFormat, triggerKeyup, getRichEditorContent, changeContent, validateEditorContentOnInsertHtml, loadResource } from "../../../utils/editorUtils"; //import './ZohoDeskEditor_Init'; /***** components *****/ import styles from "./TextEditor.module.css"; /* eslint-disable camelcase */ /* eslint-disable no-undef */ /* eslint-disable react/no-deprecated */ export default class TextEditor extends Component { constructor(props) { super(props); this.state = { isEditorLoad: false, isResourceLoaded: false, isEditorShow: false }; let methods = ['editorCallback', 'handleUpload', 'handleChange', 'focusCallback', 'handleInlineUpload', // 'handleDropUpload', 'blurCallback', 'handleGetContent', 'initializeEditor', 'clearEditorData', 'plainTextSwitchCallback', 'onWindowClick', 'toggleEditor']; bind.apply(this, methods); } componentDidMount() { this.mount = true; if (typeof global.ZohoDeskEditor === 'undefined') { loadResource(this.props.EDITORURL, 'js', 'ZohoDeskEditor').then(() => { this.setState({ isResourceLoaded: true }); }); } else { this.setState({ isResourceLoaded: true }); } window.addEventListener('click', this.onWindowClick); } initializeEditor(id, mode) { let { value, editorMode = '', editorOptions = {}, needEditorFocus = true, // handleDropUpload, fontFamily, fontSize, initCallback, handleAlertMessage, needInlineAttachment, customInitOption } = this.props; if (id && global.ZohoDeskEditor) { let defaultObj = { id, content: fixEncoding(value), callback: this.editorCallback, imageuploadcallback: this.handleInlineUpload, // handleInlineDropImage: handleDropUpload ? this.handleDropUpload : undefined, contentChanged: this.handleChange, focusCallback: this.focusCallback, lineHeight: 'Normal', backgroundColor: 'transparent', defaultfontsize: '14px', allowTagsInsertHTML: ['iframe'], allowAttrsInsertHTML: ['frameborder', 'allowfullscreen'], needEditorFocus, blurCallback: this.blurCallback, mode, handleAlertMessage: handleAlertMessage, plainTextSwitchCallback: this.plainTextSwitchCallback, imgAspect: true, handleInlineDropImage: needInlineAttachment ? this.handleInlineUpload : null, needInlineAttachHandling: needInlineAttachment, hookOnInsertHTML: validateEditorContentOnInsertHtml, needCustomPaste: function (event, editorObj) { return true; // By default reply editor needs customPaste, so returning true. }, htmlVersion: '<!Doctype html>' }; if (!customInitOption) { if (!ZohoDeskEditor_Init.init) { global.editorInitialize && global.editorInitialize(); } ZohoDeskEditor_Init.init(editorMode, fontFamily, initCallback, fontSize); } defaultObj = Object.assign(defaultObj, editorOptions); const globalEditor = global.ZohoDeskEditor; globalEditor && typeof globalEditor.create == 'function' && globalEditor.create(defaultObj, customInitOption); } } plainTextSwitchCallback() { let { plainTextSwitchCallback, id } = this.props; let content = this.handleGetContent(); plainTextSwitchCallback && plainTextSwitchCallback(content, id); } clearEditorData(id) { let { getRef } = this.props; if (global.editor && global.editor[id]) { delete global.editor[id]; } getRef && getRef(null); } UNSAFE_componentWillReceiveProps(np) { let { changeEditorContent } = this.props; let id = np.id; let editorObj = global.editor ? global.editor[id] ? global.editor[id] : {} : {}; if (np.isEmptyContent && editorObj) { editorObj.setContent(''); } if (typeof changeEditorContent !== 'undefined' && np.changeEditorContent != changeEditorContent && np.changeEditorContent) { changeContent(id, np.value); } } componentDidUpdate(prevProps, prevState) { let { id, value, shouldUpdateContent, mode } = this.props; let { isResourceLoaded } = this.state; if (prevProps.id !== id) { global.editor[id] = global.editor[prevProps.id]; delete global.editor[prevProps.id]; shouldUpdateContent && changeContent(id, value); } if (prevState.isResourceLoaded !== isResourceLoaded && isResourceLoaded) { this.initializeEditor(id, mode); } } componentWillUnmount() { this.mount = false; this.clearEditorData(this.props.id); window.removeEventListener('click', this.onWindowClick); } focusCallback() { let { onFocus } = this.props; onFocus && onFocus(); } handleGetContent() { let { id } = this.props; let editorObj = global.editor[id] ? global.editor[id] : {}; let content = getRichEditorContent(id); if (!editorContentValidate(editorObj)) { content = ''; } content = content.trim(); return content; } handleChange() { let { onChange, id } = this.props; if (onChange) { let content = this.handleGetContent(); onChange(content, id); } } editorCallback(editorObj) { let { editorCallback, getRef, isCustomScroll, customCSS } = this.props; this.setState({ isEditorLoad: true, isEditorShow: true }); let { id } = this.props; global.editor = global.editor || {}; if (!global.editor[id]) { global.editor[id] = editorObj; } editorCallback && editorCallback(editorObj); const iframe = selectn('iframe.contentDocument.body', editorObj) || null; const iframeHead = selectn('iframe.contentDocument.head', editorObj) || null; getRef && getRef(iframe); if (iframe) { iframe.addEventListener('click', () => editorObj.iframe.click()); if (isCustomScroll) { let link = document.createElement('style'); link.innerText = "body{font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 0}.scroll{--zd-scroll-width:12px;--zd-scroll-height:12px;--zd-scroll-bg:rgba(255,255,255,0.1);--zd-scroll-corner-bg:transparent;--zd-scroll-thump:rgba(44,51,77,0.2);--zd-scroll-thump-hoverbg:rgba(44,51,77,0.3);--zd-scroll-border:rgba(44,51,77,0.1)}.scroll[data-scroll-palette='dark'],.scroll [data-scroll-palette='dark']{--zd-scroll-thump:rgba(255,255,255,0.2);--zd-scroll-thump-hoverbg:rgba(255,255,255,0.4);--zd-scroll-border:rgba(255,255,255,0.07)}.scroll,.scroll *{scrollbar-color:var(--zd-scroll-thump) var(--zd-scroll-bg);scrollbar-width:thin;-ms-scrollbar-highlight-color:var(--zd-scroll-bg);-ms-scrollbar-face-color:var(--zd-scroll-thump)}.scroll::-webkit-scrollbar,.scroll ::-webkit-scrollbar{background:var(--zd-scroll-corner-bg)}.scroll::-webkit-scrollbar:hover,.scroll ::-webkit-scrollbar:hover{background:var(--zd-scroll-bg)}.scroll::-webkit-scrollbar:horizontal,.scroll ::-webkit-scrollbar:horizontal{height:var(--zd-scroll-height)}.scroll::-webkit-scrollbar:vertical,.scroll ::-webkit-scrollbar:vertical{width:var(--zd-scroll-width)}.scroll::-webkit-scrollbar-button,.scroll ::-webkit-scrollbar-button{display:none;width:0;height:0}.scroll::-webkit-scrollbar-track:vertical,.scroll ::-webkit-scrollbar-track:vertical{border-left:1px solid transparent;border-right:1px solid transparent}.scroll::-webkit-scrollbar-track:vertical:hover,.scroll ::-webkit-scrollbar-track:vertical:hover{border-color:var(--zd-scroll-border)}.scroll::-webkit-scrollbar-track:horizontal,.scroll ::-webkit-scrollbar-track:horizontal{border-top:1px solid transparent;border-bottom:1px solid transparent}.scroll::-webkit-scrollbar-track:horizontal:hover,.scroll ::-webkit-scrollbar-track:horizontal:hover{border-color:var(--zd-scroll-border)}.scroll::-webkit-scrollbar-track-piece,.scroll ::-webkit-scrollbar-track-piece{background:inherit}.scroll::-webkit-scrollbar-thumb,.scroll ::-webkit-scrollbar-thumb{border-radius:10px;background:var(--zd-scroll-thump);background-clip:padding-box;border:3px solid transparent}.scroll::-webkit-scrollbar-thumb:hover,.scroll ::-webkit-scrollbar-thumb:hover{background:var(--zd-scroll-thump-hoverbg);background-clip:padding-box;border:3px solid transparent}.scroll::-webkit-scrollbar-corner,.scroll ::-webkit-scrollbar-corner{background:var(--zd-scroll-corner-bg)}.scroll::-webkit-resizer,.scroll::-webkit-resizer{background:inherit}"; iframeHead.appendChild(link); iframe.classList.add('scroll'); } let customStyleTag = document.createElement('style'); customStyleTag.type = 'text/css'; const customizedCSS = `pre {white-space: pre-wrap} ${customCSS}`; const fontCSS = `@font-face {font-family: 'ZohoPuviRegular';src: url('https://static.zohocdn.com/zohofonts/zohopuvi/4.0/Zoho_Puvi_Regular.woff2') format('woff2');font-style: normal;font-weight: normal;text-rendering: optimizeLegibility;font-display: swap}@font-face {font-family: Regular;src: url('https://static.zohocdn.com/webfonts/lato2regular/font.woff2') format('woff2');font-weight: 400;font-style: normal;font-display: swap}@font-face {font-family: 'RobotoRegular';font-weight: 400;font-style: normal;font-display: swa;src: url('https://static.zohocdn.com/webfonts/robotoregular/font.woff2')}`; customStyleTag.textContent = `${customizedCSS} ${fontCSS}`; iframeHead.appendChild(customStyleTag); } } handleInlineUpload(file, successCallback, failureCallback, mode, editorObj) { let { id, setInlineAttachmentInProgress: progress, i18nKeys, inlineImageProps } = this.props; const { fileUploadError, fileNotSupported, fileSizeLimitExceed, fileEmptyError, fileNameLimitExceed } = i18nKeys; const { allowedFileExtensions = ["jpeg", "jpg", "png", "gif", "bmp", "ico"], fileNameMaxCharacters = 200, fileSizeMaxBytes = 3 * 1024 * 1024 } = inlineImageProps; if (!isFileNameSizeInvalid(file.name, fileNameMaxCharacters)) { if (file.size != 0) { if (file.size <= fileSizeMaxBytes) { if (isImageFormat(file.name, allowedFileExtensions)) { progress && progress(true); this.handleUpload(file).then(res => { successCallback(res); progress && progress(false); if (id && editorObj) { triggerKeyup(editorObj.doc); } }, () => { failureCallback(fileUploadError); }); } else { failureCallback(fileNotSupported); } } else { failureCallback(fileSizeLimitExceed); } } else { failureCallback(fileEmptyError); } } else { failureCallback(fileNameLimitExceed); } } // handleDropUpload(file, successCallback, failureCallback) { // let e = { target: { files: [file] } }; // let { handleDropUpload } = this.props; // handleDropUpload(e).then( // (res) => { // successCallback(res); // }, // () => { // failureCallback(); // } // ); // } blurCallback() { let { blurCallback } = this.props; let content = this.handleGetContent(); blurCallback && blurCallback(content); } handleUpload(file) { let { onUpload, editorMode, getCSRFCookieName, getCSRFCookie } = this.props; try { let formData = new FormData(); formData.append('img_file', file, file.name); if (getCSRFCookieName && getCSRFCookie) { formData.append(getCSRFCookieName(), getCSRFCookie()); } return onUpload(formData, file); } catch (err) { return Promise.reject(); } } onWindowClick(e) { let { isEditorDefaultOpen } = this.props; let element = e.target; if (!element.closest('[data-isEditor]') && !element.closest("[id='KB_Editor_UploadImage_Popup']") && !element.closest("[id='KB_Editor_Overlay']") && !element.closest('.zdeskEditor_popup') && element && typeof element.className === 'string' && !element.className.startsWith('KB') && !element.hasAttribute('data-insertoptions') && !element.closest('.KB_Editor_common_DropDown')) { let { value = '', id } = this.props; let cont = value; if (typeof editor !== 'undefined') { cont = editor['addFormEditor'] && editor['addFormEditor'].getContent(); } if (!isEditorDefaultOpen) { if ((cont == '' || cont == '<div><br></div>') && this.mount) { this.toggleEditor(false); } } } } toggleEditor(value) { let { toggleEdit } = this.props; toggleEdit && toggleEdit(value); } render() { let { id, dataId, type, border, ImgLazyLoad, loadingComponent, isNightMode, isReadOnly, dataSelectorId, isDisabled } = this.props; let { isEditorLoad, isEditorShow } = this.state; let editorDoc = ImgLazyLoad && global.editor && global.editor[id] ? global.editor[id].doc : null; return /*#__PURE__*/React.createElement(Container, { className: `${styles.textEditor} ${styles[type]} ${styles[border]} ${isNightMode ? styles.night : styles.light} ${isReadOnly ? styles.readOnly : ''} ${isDisabled ? styles.disable : ''} ${!isEditorShow ? styles.editorHide : ''}`, dataId: dataId, "data-isEditor": true, dataSelectorId: dataSelectorId }, loadingComponent && !isEditorLoad ? loadingComponent : null, /*#__PURE__*/React.createElement(Box, { flexible: true, id: id, dataId: dataId }), editorDoc && ImgLazyLoad ? /*#__PURE__*/React.createElement(ImgLazyLoad, { node: editorDoc }) : null, isReadOnly || isDisabled ? /*#__PURE__*/React.createElement("div", { className: styles.readOnlyMask }) : null); } } TextEditor.defaultProps = defaultProps; TextEditor.propTypes = propTypes; // if (__DOCS__) { // TextEditor.docs = { // componentGroup: 'Fields', // folderName: 'TextEditor' // }; // }