@zohodesk/dot
Version:
In this Library, we Provide Some Basic Components to Build Your Application
417 lines (364 loc) • 14.7 kB
JavaScript
/***** 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 = `-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}-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}-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'
// };
// }