@dotcms/react
Version:
Official React Components library to render a dotCMS page.
182 lines (179 loc) • 5.74 kB
JavaScript
import { jsx } from 'react/jsx-runtime';
import { Editor } from '@tinymce/tinymce-react';
import { useRef, useState, useEffect } from 'react';
import { UVE_MODE, DotCMSUVEAction } from '@dotcms/types';
import { __DOTCMS_UVE_EVENT__ } from '@dotcms/types/internal';
import { getUVEState, sendMessageToUVE } from '@dotcms/uve';
import { __TINYMCE_PATH_ON_DOTCMS__ } from '@dotcms/uve/internal';
import { TINYMCE_CONFIG } from './utils.esm.js';
/**
* Allows inline edit content pulled from dotCMS API using TinyMCE editor
*
* @export
* @component
* @param {Readonly<DotCMSEditableTextProps>} props {
* mode = 'plain',
* format = 'text',
* contentlet,
* fieldName = ''
* }
* @example
* ```javascript
* import { DotCMSEditableText } from '@dotcms/react';
*
* const MyContentletWithTitle = ({ contentlet }) => (
* <h2>
* <DotCMSEditableText
* contentlet={contentlet}
* fieldName="title"
* mode='full'
* format='text'/>
* </h2>
* );
* ```
* @returns {JSX.Element} A component to edit content inline
*/
function DotCMSEditableText({
mode = 'plain',
format = 'text',
contentlet,
fieldName
}) {
const editorRef = useRef(null);
const [scriptSrc, setScriptSrc] = useState('');
const [initEditor, setInitEditor] = useState(false);
const [content, setContent] = useState((contentlet == null ? void 0 : contentlet[fieldName]) || '');
useEffect(() => {
setContent((contentlet == null ? void 0 : contentlet[fieldName]) || '');
}, [fieldName, contentlet]);
useEffect(() => {
var _state$dotCMSHost, _editorRef$current;
const state = getUVEState();
setInitEditor((state == null ? void 0 : state.mode) === UVE_MODE.EDIT && !!(state != null && (_state$dotCMSHost = state.dotCMSHost) != null && _state$dotCMSHost.length));
if (!contentlet || !fieldName) {
console.error('[DotCMSEditableText]: contentlet or fieldName is missing', 'Ensure that all needed props are passed to view and edit the content');
return;
}
if (state && state.mode !== UVE_MODE.EDIT) {
console.warn('[DotCMSEditableText]: TinyMCE is not available in the current mode');
return;
}
if (!(state != null && state.dotCMSHost)) {
console.warn('[DotCMSEditableText]: The `dotCMSHost` parameter is not defined. Check that the UVE is sending the correct parameters.');
return;
}
const createURL = new URL(__TINYMCE_PATH_ON_DOTCMS__, state.dotCMSHost);
setScriptSrc(createURL.toString());
const content = (contentlet == null ? void 0 : contentlet[fieldName]) || '';
(_editorRef$current = editorRef.current) == null || _editorRef$current.setContent(content, {
format
});
}, [format, fieldName, contentlet, content]);
useEffect(() => {
var _getUVEState;
if (((_getUVEState = getUVEState()) == null ? void 0 : _getUVEState.mode) !== UVE_MODE.EDIT) {
return;
}
const onMessage = ({
data
}) => {
const {
name,
payload
} = data;
if (name !== __DOTCMS_UVE_EVENT__.UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS) {
return;
}
const {
oldInode,
inode
} = payload;
const currentInode = contentlet.inode;
const shouldFocus = currentInode === oldInode || currentInode === inode;
if (shouldFocus) {
var _editorRef$current2;
(_editorRef$current2 = editorRef.current) == null || _editorRef$current2.focus();
}
};
window.addEventListener('message', onMessage);
return () => {
window.removeEventListener('message', onMessage);
};
}, [contentlet == null ? void 0 : contentlet.inode]);
const onMouseDown = event => {
var _editorRef$current3;
const {
onNumberOfPages = 1
} = contentlet;
const {
inode,
languageId: language
} = contentlet;
if (Number(onNumberOfPages) <= 1 || (_editorRef$current3 = editorRef.current) != null && _editorRef$current3.hasFocus()) {
return;
}
event.stopPropagation();
event.preventDefault();
sendMessageToUVE({
action: DotCMSUVEAction.COPY_CONTENTLET_INLINE_EDITING,
payload: {
dataset: {
inode,
language,
fieldName
}
}
});
};
const onFocusOut = () => {
var _editorRef$current4, _editorRef$current5;
const editedContent = ((_editorRef$current4 = editorRef.current) == null ? void 0 : _editorRef$current4.getContent({
format: format
})) || '';
const {
inode,
languageId: langId
} = contentlet;
if (!((_editorRef$current5 = editorRef.current) != null && _editorRef$current5.isDirty()) || !didContentChange(editedContent)) {
return;
}
sendMessageToUVE({
action: DotCMSUVEAction.UPDATE_CONTENTLET_INLINE_EDITING,
payload: {
content: editedContent,
dataset: {
inode,
langId,
fieldName
}
}
});
};
const didContentChange = editedContent => {
return content !== editedContent;
};
if (!initEditor) {
// We can let the user pass the Child Component and create a root to get the HTML for the editor
return jsx("span", {
dangerouslySetInnerHTML: {
__html: content
}
});
}
return jsx("div", {
style: {
outline: '2px solid #006ce7',
borderRadius: '4px'
},
children: jsx(Editor, {
tinymceScriptSrc: scriptSrc,
inline: true,
onInit: (_, editor) => editorRef.current = editor,
init: TINYMCE_CONFIG[mode],
initialValue: content,
onMouseDown: onMouseDown,
onFocusOut: onFocusOut
})
});
}
export { DotCMSEditableText };